SQLite - Una breve intro

Hace varios años conocí SQLite, una excelente base de datos escrita por D. Ricard Hipp, quien también escribió otros proyectos como CVSTrac (sirvió de inspiración para el famoso The Trac), Fossil-SCM el scm que adoro, entre otros proyectos. La idea de escribir sobre SQLite mientras leía el artículo sobre SQLite en el IPhone

Lo que me gusta de SQLite es que su API es muy sencilla y que cuanta con cosas para los perezosos (”sqlite3_execute”) y con cosas para personas que piensan que lo primordial es el performance. Un código vale más que mil palabras, miren un pequeño ejemplo de SQLite…

/**
 * Coded by crodas,
 *
 * The author disclaims the copyright of this code.
 */
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>

int table_exists(sqlite3 * dbh, const char * table) {
    sqlite3_stmt* pStmtPrep;
    int rc,exists;
    /* preparamos el SQL a ejecutar, muy util para evitar SQL injections */
    rc=sqlite3_prepare(dbh,"select * from sqlite_master where type='table' and name=?",-1 /* null terminated str*/, &pStmtPrep,NULL);
    if (rc!=SQLITE_OK) {
        printf("This is an SQL bug %s",sqlite3_errmsg(dbh));
        exit(-1);
    }

    /* asignamos a la primera variabla (?) el valor de table*/
    sqlite3_bind_text(pStmtPrep,1,table,-1,0);

    /* ejecutamos */
    rc = sqlite3_step(pStmtPrep);
    switch(rc) {
        case SQLITE_ERROR:
        case SQLITE_BUSY:
            printf("Database locked or unknown error");
            fflush(stdout);
            exit(-1);
            break;
        case SQLITE_DONE:
            exists = -1; /* no existe */
            break;
        case SQLITE_ROW:
            exists = 1; /* existe */

    }

    /* a liberar memoria! */
    sqlite3_finalize(pStmtPrep);
    return exists;
}

int main() {
    sqlite3 *  dbh;
    int rc,i;
    sqlite3_stmt* pStmtPrep;

    if (sqlite3_open_v2("test.db",&dbh,SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,0)!=SQLITE_OK) {
        printf("Can't  open db, please check permissions on this folder. %s\n",sqlite3_errmsg(dbh));
        return -1;
    }

    /**
     *  Hice una pequenha funcion que ve si existe.
     *  lo bueno de la funcion es que muestra el primer ejemplo
     *  el SQLPrepare, y muestra como saber si la consulta
     *  tiene resultado o no
     */
    if (table_exists(dbh,"testing")==-1) {
        printf("Table doesn't exists,execute\n");
        /* tabla sencilla, utilizo exec porque no espero resultado */
        sqlite3_exec(dbh,"create table testing (id int, text varchar(250))",0,0,0);
        /* sql preparada para el insert */

        int data_id[] = {5,5,5,8,0}; /* el ID no es PK, en la vida real seria PK*/
        const char*  data_data[] = {"Some text","Another text","foobar","This is the 8 text",0};
        rc=sqlite3_prepare(dbh,"insert into testing values(?,?)",-1, &pStmtPrep,NULL);
        /* no controlo nada porque ya mostre en la funcion anterior como controlar errores */
        for(i=0;;i++) {
            if (data_id[i] == 0) break;
            /* cambiamos ? ? por sus valores */
            sqlite3_bind_int(pStmtPrep,1,data_id[i]);
            sqlite3_bind_text(pStmtPrep,2,data_data[i],-1,0);

            /* ejecutamos */
            rc=sqlite3_step(pStmtPrep);
            /* se tendria que controlar la salida*/

            /* ya que no hay ciclos, para cambiar los parametros */
            /* debemos reinicar al Statement */
            sqlite3_reset(pStmtPrep);
        }

        sqlite3_finalize(pStmtPrep);
    }

    /* ahora queremos los datos con id 5,6,7,8 */
    int data[] = {5,6,7,8,0};
    char * text;
    rc=sqlite3_prepare(dbh,"select * from testing where id=?",-1 /* null terminated str*/, &pStmtPrep,NULL);
    /* no controlo nada porque ya mostre en la funcion anterior como controlar errores */
    for(i=0;;i++) {
        if (data[i] == 0) break;
        /* asignar valor a ? */
        sqlite3_bind_int(pStmtPrep,1,data[i]);
        /* mientas haya resultado */
        while (sqlite3_step(pStmtPrep)==SQLITE_ROW) {
            text = sqlite3_column_text(pStmtPrep,1); /* id = 0, text=1 */
            printf("%d: %s\n",data[i],text);
        }

        /* reinicar el stmt */
        sqlite3_reset(pStmtPrep);
    }

    /* */
    sqlite3_finalize(pStmtPrep);

    sqlite3_close(dbh);
}

Lo que me gusta es que tenemos a toda una base de datos relacional en nuestro programa, y si de rendimiento se trata se puede hacer “prepare” de todas las consultas SQL al principio del programa y luego ir ejecutando, no es cosa complicada,  se ahoraría un montón de tiempo y procesador.

Otra cosa que me gusta mucho es que fácilmente extendible, una vez necesitaba una función para comprimir y descomprimir (la función compress y decompress del MySQL), envíe mi consulta en la lista de SQLite, y Dr. Hipp me respondío lo siguiente:

/*
** SQL function to compress content into a blob using libz
*/
static void compressFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  int nIn, nOut;
  long int nOut2;
  const unsigned char *inBuf;
  unsigned char *outBuf;
  assert( argc==1 );
  nIn = sqlite3_value_bytes(argv[0]);
  inBuf = sqlite3_value_blob(argv[0]);
  nOut = 13 + nIn + (nIn+999)/1000;
  outBuf = malloc( nOut+4 );
  outBuf[0] = nIn>>24 & 0xff;
  outBuf[1] = nIn>>16 & 0xff;
  outBuf[2] = nIn>>8 & 0xff;
  outBuf[3] = nIn & 0xff;
  nOut2 = (long int)nOut;
  compress(&outBuf[4], &nOut2, inBuf, nIn);
  sqlite3_result_blob(context, outBuf, nOut2+4, free);
}

/*
** An SQL function to decompress.
*/
static void uncompressFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  unsigned int nIn, nOut, rc;
  const unsigned char *inBuf;
  unsigned char *outBuf;
  long int nOut2;

  assert( argc==1 );
  nIn = sqlite3_value_bytes(argv[0]);
  if( nIn<=4 ){
    return;
  }
  inBuf = sqlite3_value_blob(argv[0]);
  nOut = (inBuf[0]<<24) + (inBuf[1]<<16) + (inBuf[2]<<8) + inBuf[3];
  outBuf = malloc( nOut );
  nOut2 = (long int)nOut;
  rc = uncompress(outBuf, &nOut2, &inBuf[4], nIn);
  if( rc!=Z_OK ){
    free(outBuf);
  }else{
    sqlite3_result_blob(context, outBuf, nOut2, free);
  }
}

/* Make the functions above accessible to SQLite as follows:
*/
  sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
     compressFunc, 0, 0);
  sqlite3_create_function(db, "uncompress", 1, SQLITE_UTF8, 0,
     uncompressFunc, 0, 0);

Como vieron no es cosa de otro mundo, muy sencillo, y ya extendimos SQLite!. Ahora que estaré de vacaciones empiezaré a jugar con el SQlite VFS, veremos que sale…

Seven Things you might not know about me

Last week I was “pinged” by two Brazilians friends (Augusto and Bruno “Porkaria”) to follow a funny chain of blog posts, and I read a lot about this on several blogs and it is funny, I never thought that I’d could be included in the circle, so now I’m in, so here I come (I apologise, probably I am not very interesting).

  1. I start coding with Visual Basic 5 (my dark side), then I switch to PHP3.
  2. I love Metal Music (heavy, death, black, heavy), and to me there is not other kind of music.
  3. I disliked PHP5 ‘coz it’s look as a Java’s ripe off, but now I am trying out, and it looks nice, probably I will drop off PHP4 soon.
  4. I’d like to be a designer, but it’s really really hard, I know CSS and the basic of GIMP, but still I don’t have inspiration,
  5. I want to work outside this country ASAP, and no one wants to hire me, I think I need to finish my University first, :(
  6. I am coke addict, I can’t live without it (1l per day), I need to leave it ASAP,
  7. I don’t like beer nor Whisky, I prefer Sprite + sugar + Vodka.

Now let’s choose seven people (I don’t warranty they will follow this chain):

  • Richardo Galli: He is a PHP/Ninja, a great GTalk friend, and the creator of Menéame.net, He is the second guy that I met with a profile in Wikipedia (English && Spanish).
  • Manuel Lemos: The greatest PHPDev I meet in person, I don’t think he will write about this (usually he is busy), but let’s try.
  • Matias Insaurralde: He is a “Railer” but I am PHPzing him… soon he will be a great PHPdev.
  • Felipe Ribeiro: A great friend, he taught me ’bout the RESTful in one great talk in ConaPHP 2008.
  • Pablo Castillo: Great developer, great friend… together we’re planning to move this poor country.
  • Matt Mullenweg: Everybody knows him, I meet him at the Latinoware 2008, very nice person.
  • Matias Montes: I meet him at the Latinoware 2008, great speecher, great PHPdev.

I have several other friend, but probably they already done this, or they don’t have a blog (as my friend Cristian Medeiros, come on man open a blog!)

Rules are quite simple:

- Link your Original tagger(s), and list these rules on you blog

- Share seven facts about yourself in the post - some random, some weird.

- Tag seven people at the end of your post by leaving their names and the links to their blogs.

- Let them know they’ve been tagged by leaving a comment on their blogs and/or Twitter.

“You type, we guess” (mi nuevo juguete)

Les presento mi nuevo jueguete, Language Guess, una pagina que hice para poner en practica mis conocimientos sobre clasificación de textos, al mismo tiempo para poner en producción mi futura contribución para PHPClasses y crear mi primer webservice RESTful (esta ultima parte todavía no termine).

Algunos de mis beta testers (osea gtalk-friends) creyeron al principio que solo utilizaba el API de Google, cosa que ni sabia que existía. Afortunadamente hace algún tiempo atrás pude ver la luz al leer el Paper que cambio mi forma de pensar, desde ahí me tuve la idea de armar un como languess.com, hasta que finalmente le gané a la pereza y ahí lo tienen.

Obviamente es casi imposible que sea perfecto, pero según mis pruebas detectaba bastante bien. Claro que si se equivoca se le puede enseñar y la próxima vez que genere los n-gramas aprenderá mejor.

Ahora mismo languess aprendió Español, Ingles, Francés y Portugués teniendo como ejemplo la Santa Biblia (obviamente en cada idioma citado), y por su parte Alemán y Esperanto gracias a los ejemplos proveídos por Matias que hizo un script en 5 min. (probablemente en ruby) que extrae textos de Wikipedia. Si alguien tiene textos puede enviarme a mi mail asi Languess puede aprender mas y mas idiomas (no se necesitan muchos textos de ejemplos, pero mientras mas mejor), seria genial si alguien puede enviarme algo de Guaraní.

Para el futuro queda afinar el detector para que sea casi perfecto, para ello creo que tengo que afinar el método de aprendizaje, pero hay una sola forma de saber, con las pruebas de los visitantes.

Saludos a todos, y feliz año 2009.

La “blogosfera” Paraguaya en un solo lugar…

Hace dos días, si mal no recuerdo, entre en contacto con César Sanchez, paraguayo que vive en Argentina, y chateando surgió la idea de hacer una página para mostrar los blogs nacionales, aprovechando que desde hace algún tiempo he querido hacer algo similar pero no tan elitista (como los actuales) sobre PHP (http://phpne.ws).

A simple vista parece una simple instalación del los Planetarios (ej: Planet PHP), pero no, aunque el diseño es totalmente copiado (como podrán ver, no soy diseñador.. diseñadores.. donde estan??) el código no tiene nada que ver con el Planetario. Se preguntaran por que… y simplemente porque yo quería usar mis clases y armar algo 100% paraguayo y que funcione con PHP4 y PHP5. Además ya que programé toda la página es sencilla extender.

Ahora lo que estoy viendo que haría falta es organizar los posts por temas, ciudades, departamentos e idiomas, para que sea más útil, comentarios y sugerencias son bienvenidos.

Los fuentes del sitio son está muy beta, pero si la gente está interesada puedo estructurar mejor y liberar como Open Source (claro como BSD).

PyGosfera es el nombre, como se darán cuenta no soy muy creativo, también se aceptan sugerencias para nombre nuevo… :)

Saludos y que lo disfruten.

El nuevo jueguete.. “is out”

Después de el lanzamiento de File S3, gracias al feedback de los diggers y de amigos, me sentí realizado ya que pude dejar la pereza a un lado y comenzar a hacer sitios webs que tengo planeado desde hace varios meses o inclusos años.

Ahora les presento mi nuevo juguete read2.us (Read to us), un página web que hace text to speech, es decir genera un mp3 apartir de un texto ingresado. Ahora mismo son soportados el Español y el Inglés.

Aquí les dejo una pequeña prueba de como suena. Obviamente faltan algunos detalles para el parseado mismo del texto, es decir para que lea correo electrónico, páginas webs y demás detalles que estare terminando lo más rápido posible. Read the rest of this entry »