un peu de code

Encore une fois, commençons par mettre à jour les sources :

guillaume@laptop$ cd postgresql_src/pgsql/
guillaume@laptop$ cvs -q update -d
[... coupé parce que trop long ...]
P src/interfaces/libpq/fe-exec.c
P src/interfaces/libpq/libpq-events.c
P src/interfaces/libpq/libpq-events.h
P src/interfaces/libpq/libpq-fe.h
P src/interfaces/libpq/libpq-int.h

Et on compile rapidement :

guillaume@laptop$ make && make install
[... coupé parce que trop long ...]
PostgreSQL installation complete.

Lançons PostgreSQL :

guillaume@laptop$ export PGDIR=/home/guillaume/postgresql_devel
guillaume@laptop$ export PGDATA=$PGDIR/data
guillaume@laptop$ export PATH=$PGDIR/bin:$PATH
guillaume@laptop$ pg_ctl start
server starting
FATAL:  database files are incompatible with server
DETAIL:  The database cluster was initialized with CATALOG_VERSION_NO 200809151, but the server was compiled with CATALOG_VERSION_NO 200809191.
HINT:  It looks like you need to initdb.

Oups. Tiens, la version du catalogue a changé. Il faut de nouveau exécuter initdb... c'est parti :

guillaume@laptop$ rm -rf $PGDATA/* /home/guillaume/postgresql_tblspc/*
guillaume@laptop$ initdb
The files belonging to this database system will be owned by user "guillaume".
This user must also own the server process.
[... coupé ...]
Success. You can now start the database server using:

    postgres -D /home/guillaume/postgresql_devel/data
or
    pg_ctl -D /home/guillaume/postgresql_devel/data -l logfile start

guillaume@laptop$ pg_ctl start
server starting
LOG:  database system was shut down at 2008-09-22 19:48:45 CEST
LOG:  autovacuum launcher started
LOG:  database system is ready to accept connections

C'est bon ! On doit recréer la base de données, la table et le tablespace :

guillaume@laptop$ createdb guillaume
guillaume@laptop$ psql guillaume
psql (8.4devel)
Type "help" for help.

guillaume=# CREATE TABLE t1 (id integer);
CREATE TABLE
guillaume=# CREATE TABLESPACE mon_espace_de_stockage LOCATION '/home/guillaume/postgresql_tblspc';
CREATE TABLESPACE

Voilà. On est prêt à plonger dans le code.

La première chose à faire est de modifier la syntaxe. On a vu la dernière fois que cela se passe dans le fichier src/backend/parser/gram.y (gram pour grammaire). En regardant la syntaxe déjà proposée par ALTER DATABASE, on voit qu'il est déjà possible d'ajouter une option, l'option « connection limit ». On va donc chercher cette syntaxe dans le fichier gram.y. Cherchons l'instruction ALTER DATABASE. Première occurence, le ALTER DATABASE pour le renommage d'une base de données. En fait ce code est intégré aux autres instructions de renommage des objets. Ça ne nous intéresse pas. Occurence suivante, le ALTER DATABASE pour changer le propriétaire. Là aussi, ce code est intégré aux autres instructions de changement de propriétaire. Ça ne nous intéresse toujours pas. Occurence suivante. Ah, une partie complète sur ALTER DATABASE. Le jeton AlterDatabaseStmt est celui qui nous intéresse. « ALTER DATABASE database_name opt_with alterdb_opt_list » correspond au « ALTER DATABASE database_name WITH CONNECTION LIMIT x ». « alterdb_opt_list » correspond à la liste des options, pour l'instant qui se limite à une, mais nous devons en ajouter une deuxième. Cherchons donc maintenant « alterdb_opt_list ». Nous trouvons ce code :

alterdb_opt_list:
			alterdb_opt_list alterdb_opt_item		{ $$ = lappend($1, $2); }
			| /* EMPTY */							{ $$ = NIL; }
		;

Cela déclare « tout simplement » une liste. Nous devons maintenant chercher « alterdb_opt_item », et nous trouvons ceci :

alterdb_opt_item:
			CONNECTION LIMIT opt_equal SignedIconst
				{
					$$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
				}
		;

Si on essaie d'analyser cela, on comprend que la chaîne précise les mots fixes (« CONNECTION LIMIT »), un jeton pour le symbole d'égalité et un SignedIconst qui est un jeton correspondant à une constante entière signée (Signed Integer Constant). Il nous faut ajouter la syntaxe pour le tablespace :

alterdb_opt_item:
			CONNECTION LIMIT opt_equal SignedIconst
				{
					$$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
				}
			| TABLESPACE name
				{
					$$ = makeDefElem("tablespace", (Node *)makeString($2));
				}
		;

C'est-à-dire le mot fixe TABLESPACE suivi du nom du tablespace. « name » n'est pas juste la traduction bête, mais un jeton représentant le nom d'un objet PostgreSQL.

Et maintenant que doit faire cette nouvelle syntaxe ? Nous avons vu la dernière fois que le fichier backend/commands/tablecmds.c gérait tout ce qui concernait les commandes relatives aux tables. Peut-être existe-il la même chose pour les bases. Cherchons ça :

guillaume@laptop$ ll src/backend/commands/ | grep base
guillaume@laptop$ ll src/backend/commands/ | grep db
-rw-rr 1 guillaume guillaume  46550 2008-09-22 22:37 dbcommands.c
-rw-rr 1 guillaume guillaume  22084 2008-09-22 22:37 dbcommands.o

backend/commands/dbcommands.c semble être le bon fichier. Ouvrons le fichier et cherchons le texte « ALTER DATABASE ». On arrive directement sur une fonction qui prend en argument une structure AlterDatabaseStmt. Hmmm, mais c'est le jeton que nous avons modifié... excellent, ça. En lisant le code de la fonction, on voit cette partie :

if (strcmp(defel->defname, "connectionlimit") == 0)
{
  if (dconnlimit)
    ereport(ERROR,
      (errcode(ERRCODE_SYNTAX_ERROR),
      errmsg("conflicting or redundant options")));
    dconnlimit = defel;
}

C'est le code qui s'occupe de l'option CONNECTION LIMIT. Il nous reste à ajouter le code pour l'option TABLESPACE. Nous allons seulement ajouter un code qui envoie un message dans les journaux applicatifs pour savoir si nous avons bien réussi à intégrer une nouvelle syntaxe. Cela donne ce code :

else if (strcmp(defel->defname, "tablespace") == 0)
{
  elog(NOTICE, "set tablespace !");
}

Simple, non ?

Voyons déjà ce que donne ces modifications. On compile, installe et redémarre PostgreSQL :

guillaume@laptop$ make && make install
[... coupé de nouveau ...]
make1: quittant le répertoire « /home/guillaume/postgresql_src/pgsql/config »
PostgreSQL installation complete.
guillaume@laptop$ pg_ctl restart
waiting for server to shut down....
LOG:  received smart shutdown request
LOG:  autovacuum launcher shutting down
LOG:  shutting down
LOG:  database system is shut down
 done
server stopped
server starting
LOG:  database system was shut down at 2008-09-22 22:36:28 CEST
LOG:  autovacuum launcher started
LOG:  database system is ready to accept connections

Lançons psql :

guillaume@laptop$ psql postgres
psql (8.4devel)
Type "help" for help.

postgres=# alter database guillaume with tablespace mon_espace_de_stockage ;
NOTICE:  set tablespace !
ALTER DATABASE

L'ajout de la syntaxe a fonctionné \o/

Maintenant, il va falloir ajouter un code plus intéressant dans cette fonction.