diff --git a/casse-noisettes.html b/casse-noisettes.html
index a761d98f25e5f8c7c8025c43fc0e53e89ebccaa7..be4c6312c0f9e85964b29e4de801b1fb90e526ff 100644
--- a/casse-noisettes.html
+++ b/casse-noisettes.html
@@ -41,11 +41,12 @@
 </table>
 <hr /> 
 <table border='1' width='100%'>
-<tr><td colspan=2 align=center>Balises interdites hors boucle </td></tr>
+<tr><td colspan=2 align=center>Balises spécialement dans une boucle </td></tr>
 <tr><td>&#35;POINTS</td><td><BOUCLE_POINTS(ARTICLES){1,1}{recherche}>#POINTS</BOUCLE_POINTS></td></tr>
 <tr><td>&#35;TOTAL_BOUCLE</td><td><BOUCLE_TOTAL_BOUCLE(AUTEURS)> #TOTAL_BOUCLE</BOUCLE_TOTAL_BOUCLE></td></tr>
 <tr><td>&#35;COMPTEUR_BOUCLE</td><td><BOUCLE_COMPTEUR_BOUCLE(AUTEURS)> #COMPTEUR_BOUCLE</BOUCLE_COMPTEUR_BOUCLE></td></tr>
 <tr><td>&#35;EXPOSER</td><td><BOUCLE_EXPOSER(ARTICLES){1,1}> #EXPOSER</BOUCLE_EXPOSER></td></tr>
+<tr><td>&#35;LESAUTEURS</td><td><BOUCLE_LESAUTEURS(pgsql:ARTICLES){1,1}> #LESAUTEURS</BOUCLE_LESAUTEURS></td></tr>
 <tr><td>{titre=&#35;NOM_SITE_SPIP}</td><td><BOUCLE_TITRE2(ARTICLES){id_rubrique}{id_article=#NOM_SITE_SPIP}{"<br />"}>#ID_ARTICLE #TITRE #NOM_SITE_SPIP</BOUCLE_TITRE2></td></tr>
 <tr><td>{id_article=&#35;ID_RUBRIQUE}</td><td><BOUCLE1(RUBRIQUES){par id_rubrique}><BOUCLE_TITRE1(ARTICLES){id_rubrique}{id_article=#ID_RUBRIQUE}{"<br />"}>#ID_RUBRIQUE #ID_ARTICLE </BOUCLE_TITRE1><br />#TOTAL_BOUCLE</B_TITRE1> </BOUCLE1></td></tr>
 <tr><td>{titre=&#35;TITRE*}</td><td><BOUCLE3(RUBRIQUES){par id_rubrique}><BOUCLE_TITRE3(ARTICLES){id_rubrique}{id_article=#TITRE*}{"<br />"}>#ID_RUBRIQUE #TITRE #ID_ARTICLE </BOUCLE_TITRE3></B_TITRE3> </BOUCLE3></td></tr>
diff --git a/inc-balises.php3 b/inc-balises.php3
index 4e5df23733b10ce6bb86e69e5c0af5b9d8f6a3d2..01f424a198654c0bbbe09bdf6a8f64c81dd53cb5 100644
--- a/inc-balises.php3
+++ b/inc-balises.php3
@@ -250,7 +250,7 @@ function balise_RECHERCHE_dist($p) {
 function balise_COMPTEUR_BOUCLE_dist($p) {
 	if ($p->id_mere === '') {
 		include_local("inc-admin.php3");
-		erreur_squelette(_L("Champ #TOTAL_BOUCLE hors boucle"), $p->id_boucle);
+		erreur_squelette(_L("Champ #COMPTEUR_BOUCLE hors boucle"), $p->id_boucle);
 		$p->code = "''";
 	} else {
 		$p->code = '$compteur_boucle';
@@ -472,10 +472,17 @@ function balise_LESAUTEURS_dist ($p) {
 	if ($_lesauteurs AND $_lesauteurs != '$Pile[0][\'lesauteurs\']') {
 		$p->code = $_lesauteurs;
 	} else {
-		$_id_article = champ_sql('id_article', $p);
-
-		# On pourrait mieux faire qu'utiliser cette fonction assistante ?
-		$p->code = "sql_auteurs($_id_article)";
+		$nom = $p->id_boucle;
+	# On pourrait mieux faire qu'utiliser cette fonction assistante ?
+		$p->code = "sql_auteurs(" .
+			champ_sql('id_article', $p) .
+			",'" .
+			$nom .
+			"','" .
+			$p->boucles[$nom]->type_requete .
+			"','" .
+			$p->boucles[$nom]->sql_serveur .
+			"')";
 	}
 
 	$p->statut = 'html';
@@ -487,8 +494,16 @@ function balise_LESAUTEURS_dist ($p) {
 // Champ testant la presence d'une petition
 // non documente ???
 function balise_PETITION_dist ($p) {
-	$_id_article = champ_sql('id_article', $p);
-	$p->code = 'sql_petitions($_id_article)';
+	$nom = $p->id_boucle;
+	$p->code = "sql_petitions(" .
+			champ_sql('id_article', $p) .
+			",'" .
+			$nom .
+			"','" .
+			$p->boucles[$nom]->type_requete .
+			"','" .
+			$p->boucles[$nom]->sql_serveur .
+			"')";
 	$p->statut = 'php';
 	return $p;
 }
@@ -707,10 +722,20 @@ function balise_FORMULAIRE_ECRIRE_AUTEUR_dist($p) {
 //
 function balise_FORMULAIRE_SIGNATURE_dist($p) {
 	$_id_article = champ_sql('id_article', $p);
-
-	$p->code = '(!($petition = sql_petitions('.
-		$_id_article .
-		')) ? "" : ("<"."?php include_local(\'inc-formulaires.php3\'); lang_select(\'".$GLOBALS[\'spip_lang\']."\'); 
+	$nom = $p->id_boucle;
+	$code = "sql_petitions(" .
+			$_id_article .
+			",'" .
+			$nom .
+			"','" .
+			$p->boucles[$nom]->type_requete .
+			"','" .
+			$p->boucles[$nom]->sql_serveur .
+			"')";
+
+	$p->code = '(!($petition = '.
+		$code .
+		') ? "" : ("<"."?php include_local(\'inc-formulaires.php3\'); lang_select(\'".$GLOBALS[\'spip_lang\']."\'); 
 echo formulaire_signature(".' .
 		$_id_article .
 		'.", \'".texte_script(serialize($petition))."\'); lang_dselect(); ?".">"))';
@@ -741,5 +766,18 @@ function balise_FORMULAIRE_ADMIN_dist($p) {
 	return $p;
 }
 
-
+function balise_HTTP_dist($p) {
+	if (is_array($p->fonctions)) {
+		foreach($p->fonctions as $nom) {
+			if (is_numeric($nom))
+				$p->code = " http_status($nom);";
+			else
+				$p->code = " header($nom);";
+		}
+		$p->code = '("<" . "?php ' . $p->code . ' ?" . ">")';
+		$p->fonctions = array();
+	}
+	$p->statut = 'php';
+	return $p;
+}
 ?>
diff --git a/inc-calcul-outils.php3 b/inc-calcul-outils.php3
index ecc9c935f38a306c39ddcf8e885a32d023f38b0e..c7e855c445a05021a7ebc43b20e299756d21cf30 100644
--- a/inc-calcul-outils.php3
+++ b/inc-calcul-outils.php3
@@ -2,7 +2,7 @@
 
 //
 // Des fonctions diverses utilisees lors du calcul d'une page ; ces fonctions
-// bien pratiques n'ont guŹre de logique organisationnelle ; elles sont
+// bien pratiques n'ont guere de logique organisationnelle ; elles sont
 // appelees par certaines balises au moment du calcul des pages. (Peut-on
 // trouver un modele de donnees qui les associe physiquement au fichier
 // definissant leur balise ???
@@ -130,8 +130,6 @@ function affiche_logos($logo, $lien, $align, $flag_fichier) {
 	return $milieu;
 }
 
-
-
 //
 // fonction standard de calcul de la balise #INTRODUCTION
 // on peut la surcharger en definissant dans mes_fonctions.php3 :
@@ -188,9 +186,9 @@ function calcul_exposer ($id, $type, $reference) {
 			if ($element == 'id_secteur') $element = 'id_rubrique';
 			if (ereg("id_(article|breve|rubrique|syndic)", $element, $regs)) {
 				$exposer[$element][$id_element] = true;
-				$table = "spip_".table_objet($regs[1]);
-				list ($id_rubrique) = spip_fetch_array(spip_query(
-				"SELECT id_rubrique FROM $table WHERE $element=$id_element"));
+				list ($id_rubrique) = spip_abstract_fetch(spip_abstract_select(array(id_rubrique), 
+											       array(table_objet($regs[1])),
+											       array("$element=$id_element")));
 				$hierarchie = substr(calculer_hierarchie($id_rubrique), 2);
 				foreach (split(',',$hierarchie) as $id_rubrique)
 					$exposer['id_rubrique'][$id_rubrique] = true;
@@ -210,7 +208,7 @@ function calcul_generation ($generation) {
 							     $generation,
 							     '')),
 				       '','','','','','','');
-	while ($row = spip_fetch_array($result))
+	while ($row = spip_abstract_fetch($result))
 	  $lesfils[] = $row['id_rubrique'];
 	return join(",",$lesfils);
 }
@@ -265,34 +263,34 @@ function sql_profondeur($id)
 
 function sql_parent($id_rubrique)
 {
-  $row = spip_fetch_array(spip_query("
-SELECT id_parent FROM spip_rubriques WHERE id_rubrique='$id_rubrique'
-"));
+  $row = spip_abstract_fetch(spip_abstract_select(array(id_parent), 
+						  array(rubriques), 
+						  array("id_rubrique='$id_rubrique'")));
   return $row['id_parent'];
 }
 
 function sql_rubrique($id_article)
 {
-  $row = spip_fetch_array(spip_query("
-SELECT id_rubrique FROM spip_articles WHERE id_article='$id_article'
-"));
+  $row = spip_abstract_fetch(spip_abstract_select(array(id_rubrique),
+						  array(articles),
+						  array("id_article='$id_article'")));
   return $row['id_rubrique'];
 }
 
-function sql_auteurs($id_article)
+function sql_auteurs($id_article, $table, $id_boucle, $serveur='')
 {
   $auteurs = "";
   if ($id_article)
     {
-      $result_auteurs = spip_query("
-SELECT	auteurs.nom, auteurs.email 
-FROM	spip_auteurs AS auteurs,
-	spip_auteurs_articles AS lien
-WHERE	lien.id_article=$id_article
- AND	auteurs.id_auteur=lien.id_auteur
-");
-
-      while($row_auteur = spip_fetch_array($result_auteurs)) {
+      $result_auteurs = spip_abstract_select(array('auteurs.nom', 'auteurs.email'),
+					     array('auteurs AS auteurs',
+						   'auteurs_articles AS lien'), 
+					     array("lien.id_article=$id_article",
+						   "auteurs.id_auteur=lien.id_auteur"),
+					     '','','','',1, 
+					     $table, $id_boucle, $serveur);
+
+      while($row_auteur = spip_abstract_fetch($result_auteurs)) {
 	$nom_auteur = typo($row_auteur["nom"]);
 	$email_auteur = $row_auteur["email"];
 	if ($email_auteur) {
@@ -306,23 +304,22 @@ WHERE	lien.id_article=$id_article
   return (!$auteurs) ? "" : join($auteurs, ", ");
 }
 
-function sql_petitions($id_article) {
-	$q = spip_query("SELECT
-	id_article, email_unique, site_obli, site_unique, message, texte
-	FROM spip_petitions
-	WHERE id_article=".intval($id_article));
-	return spip_fetch_array($q);
+function sql_petitions($id_article, $table, $id_boucle, $serveur='') {
+  return spip_abstract_fetch(spip_abstract_select(array('id_article', 'email_unique', 'site_obli', 'site_unique', 'message', 'texte'),
+						  array('petitions'),
+						  array("id_article=".intval($id_article)),
+						  '','','','',1, 
+						  $table, $id_boucle, $serveur));
 }
 
 # retourne le chapeau d'un article, et seulement s'il est publie
 
 function sql_chapo($id_article)
 {
- return spip_fetch_array(spip_query("
-SELECT	chapo
-FROM	spip_articles
-WHERE	id_article='$id_article' AND statut='publie'
-"));
+  return spip_abstract_fetch(spip_abstract_select(array(chapo),
+			      array('articles'),
+			      array("id_article='$id_article'",
+				    "statut='publie'")));
 }
 
 // Calcul de la rubrique associee a la requete
@@ -331,16 +328,18 @@ WHERE	id_article='$id_article' AND statut='publie'
 function sql_rubrique_fond($contexte, $lang) {
 
 	if ($id = intval($contexte['id_rubrique'])) {
-		$row = spip_fetch_array(spip_query(
-		"SELECT lang FROM spip_rubriques WHERE id_rubrique='$id'"));
+	  $row = spip_abstract_fetch(spip_abstract_select(array('lang'),
+							  array('rubriques'),
+							  array("id_rubrique='$id'")));
 		if ($row['lang'])
 			$lang = $row['lang'];
 		return array ($id, $lang);
 	}
 
 	if ($id  = intval($contexte['id_breve'])) {
-		$row = spip_fetch_array(spip_query(
-		"SELECT id_rubrique, lang FROM spip_breves WHERE id_breve='$id'"));
+	  $row = spip_abstract_fetch(spip_abstract_select(array('id_rubrique', 'lang'),
+							  array(breves), 
+							  array("id_breve='$id'")));
 		$id_rubrique_fond = $row['id_rubrique'];
 		if ($row['lang'])
 			$lang = $row['lang'];
@@ -348,19 +347,22 @@ function sql_rubrique_fond($contexte, $lang) {
 	}
 
 	if ($id = intval($contexte['id_syndic'])) {
-		$row = spip_fetch_array(spip_query("SELECT id_rubrique
-		FROM spip_syndic WHERE id_syndic='$id'"));
+	  $row = spip_abstract_fetch(spip_abstract_select(array(id_rubrique),
+							  array(syndic),
+							  array("id_syndic='$id'")));
 		$id_rubrique_fond = $row['id_rubrique'];
-		$row = spip_fetch_array(spip_query("SELECT lang
-		FROM spip_rubriques WHERE id_rubrique='$id_rubrique_fond'"));
+		$row = spip_abstract_fetch(spip_abstract_select(array(lang),
+								array(rubriques),
+								array("id_rubrique='$id_rubrique_fond'")));
 		if ($row['lang'])
 			$lang = $row['lang'];
 		return array($id_rubrique_fond, $lang);
 	}
 
 	if ($id = intval($contexte['id_article'])) {
-		$row = spip_fetch_array(spip_query("SELECT id_rubrique,lang
-		FROM spip_articles WHERE id_article='$id'"));
+	  $row = spip_abstract_fetch(spip_abstract_select(array('id_rubrique', 'lang'),
+							  array('articles'),
+							  array("id_article='$id'")));
 		$id_rubrique_fond = $row['id_rubrique'];
 		if ($row['lang'])
 			$lang = $row['lang'];
diff --git a/inc-calcul.php3 b/inc-calcul.php3
index 5db4076937e2812d7a6a50eb1186c66bd31338e5..01ca64387ff979ce8102b0f7ab619061913eaf08 100644
--- a/inc-calcul.php3
+++ b/inc-calcul.php3
@@ -51,46 +51,57 @@ function charger_squelette ($squelette) {
 	$nom = $ext . '_' . md5($squelette);
 	$sourcefile = $squelette . ".$ext";
 
-	if (function_exists($nom)) {
-		#spip_log("Squelette $squelette:\t($nom) deja en memoire");
-		return $nom;
-	}
+	// le squelette est-il deja en memoire (<inclure> a repetition)
+	if (function_exists($nom)) return $nom;
+
 	$phpfile = 'CACHE/skel_' . $nom . '.php';
 
 		// le squelette est-il deja compile, lisible, etc ?
 	if (!squelette_obsolete($phpfile, $sourcefile)
-		AND lire_fichier ($phpfile, $contenu,
-			array('critique' => 'oui', 'phpcheck' => 'oui'))) {
+	      AND lire_fichier ($phpfile, $contenu,
+				array('critique' => 'oui', 'phpcheck' => 'oui'))) 
 		eval('?'.'>'.$contenu);
-		if (function_exists($nom))
-			return $nom;
-		}
-
-		// sinon le compiler
-	include_local("inc-compilo.php3");
-	if (!lire_fichier ($sourcefile, $skel)) { 
+	if (!function_exists($nom)) {
+		// sinon charger le compilateur et tester le source
+		include_local("inc-compilo.php3");
+		if (!lire_fichier ($sourcefile, $skel)) { 
 			// erreur webmaster : $fond ne correspond a rien
 			include_ecrire ("inc_presentation.php3");
 			install_debut_html(_T('info_erreur_squelette'));
-			echo "<P>"._T('info_erreur_squelette2',
-			array('fichier'=>$squelette))."</P>";
-			spip_log ("ERREUR: aucun squelette '$squelette' n'est disponible...");
+			echo "<p>",
+				_T('info_erreur_squelette2',
+				   array('fichier'=>$squelette)),
+				"</p>";
+			spip_log("ERREUR: squelette '$squelette' indisponible");
 			install_fin_html();
 			exit;
 		}
+	}
 
+	// ce fichier peut contenir deux sortes de choses:
+	// 1. les filtres utilisés par le squelette
+	// 2. d'eventuels ajouts a $tables_principales
+	// Le point 1 exige qu'il soit lu dans tous les cas.
+	// Le point 2 exige qu'il soit lu apres inc-compilo
+	// (car celui-ci initialise $tables_principales) mais avant la compil
+
+	$f = $squelette . '_fonctions.php3';
+	if (file_exists($f)) include($f);
+
+	if (function_exists($nom))  return $nom;
 	$skel_code = calculer_squelette($skel, $nom, $ext, $sourcefile);
-		// Tester si le compilateur renvoie une erreur
+	// Tester si le compilateur renvoie une erreur
+
 	if (is_array($skel_code)) 
-	  {
-	    erreur_squelette($skel_code[0], $skel_code[1]) ; 
-	    $skel_compile = '';
-	    $skel_code = '';
-	  }
+		{
+			erreur_squelette($skel_code[0], $skel_code[1]) ; 
+			$skel_compile = '';
+			$skel_code = '';
+		  }
 	else
-	 $skel_compile = "<"."?php\n" . $skel_code ."\n?".">";
+		$skel_compile = "<"."?php\n" . $skel_code ."\n?".">";
 
-		// Parler au debugguer
+	// Parler au debugguer
 	if ($GLOBALS['var_debug'] AND 
 	    $GLOBALS['debug_objet'] == $nom
 	    AND $GLOBALS['debug_affiche'] == 'code')
@@ -99,9 +110,10 @@ function charger_squelette ($squelette) {
 		// Evaluer le squelette
 	eval($skel_code);
 	if (function_exists($nom)) {
-			ecrire_fichier ($phpfile, $skel_compile);
-			return $nom;
-			}
+		ecrire_fichier ($phpfile, $skel_compile);
+		return $nom;
+	}
+
 		// en cas d'erreur afficher les boutons de debug
 	echo "<hr /><h2>".
 		_L("Erreur dans la compilation du squelette").
@@ -110,8 +122,6 @@ function charger_squelette ($squelette) {
 		debug_dumpfile ($skel_compile);
 }
 
-
-
 # Provoque la recherche du squelette $fond d'une $lang donnee,
 # et l'applique sur un $contexte pour un certain $cache.
 # Retourne un tableau de 3 elements:
@@ -138,7 +148,7 @@ function cherche_page ($cache, $contexte, $fond, $id_rubrique, $lang='')  {
 	$dir = "$dossier_squelettes/mon-chercher.php3";
 	if (file_exists($dir)) {
 		include($dir);
-		} else */ { 
+		} else  */ { 
 		include_local("inc-chercher.php3"); # a renommer
 	 }
 
@@ -149,13 +159,9 @@ function cherche_page ($cache, $contexte, $fond, $id_rubrique, $lang='')  {
 		$lang
 	);
 
-	/*  Idem
-	$dir = "$skel" . '_fonctions.php3';
-	if (file_exists($dir)) include($dir);
-	*/
+	// Charger le squelette et recuperer sa fonction principale
+	// (compilation automatique au besoin)
 
-	// Charger le squelette demande et recuperer sa fonction main()
-	// (on va le compiler si besoin est)
 	$fonc = charger_squelette($skel);
 
 	// Calculer la page a partir du main() du skel compile
@@ -254,7 +260,6 @@ function calculer_page_globale($cache, $contexte_local, $fond) {
 
 // Cf ramener_page +cherche_page_incluante+ cherche_page_incluse chez ESJ
 function calculer_page($chemin_cache, $elements, $delais, $inclusion=false) {
-	include_local('inc-calcul.php3');
 
 	// Inclusion
 	if ($inclusion) {
@@ -303,15 +308,13 @@ function calculer_page($chemin_cache, $elements, $delais, $inclusion=false) {
 	return $page;
 }
 
-### A passer peut-etre dans inc_db_mysql
 // Cette fonction est systematiquement appelee par les squelettes
 // pour constuire une requete SQL de type "lecture" (SELECT) a partir
 // de chaque boucle.
 // Elle construit et exe'cute une reque^te SQL correspondant a` une balise
 // Boucle ; elle notifie une erreur SQL dans le flux de sortie et termine
 // le processus.
-// Sinon, retourne la ressource interrogeable par fetch_row ou fetch_array.
-// Elle peut etre re'de'finie pour s'interfacer avec d'autres serveurs SQL
+// Sinon, retourne la ressource interrogeable par spip_abstract_fetch.
 // Recoit en argument:
 // - le tableau des champs a` ramener
 // - le tableau des tables a` consulter
@@ -323,39 +326,64 @@ function calculer_page($chemin_cache, $elements, $delais, $inclusion=false) {
 // - un compteur de sous-requete
 // - le nom de la table
 // - le nom de la boucle (pour le message d'erreur e'ventuel)
-
+// - le serveur sollicite
 
 function spip_abstract_select (
 	$select = array(), $from = array(), $where = '',
 	$groupby = '', $orderby = '', $limit = '',
 	$sousrequete = '', $cpt = '',
-	$table = '', $id = '') {
-
-	$DB = 'spip_';
-	$q = " FROM $DB" . join(", $DB", $from)
-	. ($where ? ' WHERE ' . join(' AND ', $where) : '')
-	. ($groupby ? " GROUP BY $groupby" : '')
-	. ($orderby ? "\nORDER BY $orderby" : '')
-	. ($limit ? "\nLIMIT $limit" : '');
+	$table = '', $id = '', $serveur='') {
 
-	if (!$sousrequete)
-		$q = " SELECT ". join(", ", $select) . $q;
-	else
-		$q = " SELECT S_" . join(", S_", $select)
-		. " FROM (" . join(", ", $select)
-		. ", COUNT(".$sousrequete.") AS compteur " . $q
-		.") AS S_$table WHERE compteur=" . $cpt;
-
-	//
-	// Erreur ? C'est du debug, ou une erreur du serveur
-	//
-	if (!($result = @spip_query($q))) {
-		include_local('inc-admin.php3');
-		echo erreur_requete_boucle($q, $id, $table);
+	if (!$serveur)
+	  // le serveur par defaut est celui de inc_connect.php
+	  // tout est deja pret, notamment la fonction suivante:
+	  $f = 'spip_mysql_select';
+	else {
+	  // c'est un autre; est-il deja charge ?
+		$f = 'spip_' . $serveur . '_select';
+		if (!function_exists($f)) {
+		  // non, il est decrit dans le fichier ad hoc
+			$d = 'inc_connect-' . $serveur .'.php3';
+			if (file_exists('ecrire/' . $d))
+				include_ecrire($d);
+			serveur_defini($f, $serveur);
+		}
 	}
+	return $f($select, $from, $where,
+		  $groupby, $orderby, $limit,
+		  $sousrequete, $cpt,
+		  $table, $id, $serveur);
+}
+
+function serveur_defini($f, $serveur) {
+  if (function_exists($f)) return $f;
+  include_local("inc-admin.php3");
+  erreur_squelette(_T('info_erreur_squelette'),
+		   $serveur . 
+		   _L(' serveur SQL indefini'));
+}
+
+// Les 3 fonctions suivantes exploitent le resultat de la precedente,
+// si l'include ne les a pas definies, erreur immediate
 
-#	 spip_log(spip_num_rows($result) . $q);
-	return $result;
+function spip_abstract_fetch($res, $serveur='')
+{
+  if (!$serveur) return spip_fetch_array($res);
+  $f = serveur_defini('spip_' . $serveur . '_fetch', $serveur);
+  return $f($res);
 }
 
+function spip_abstract_count($res, $serveur='')
+{
+  if (!$serveur) return spip_num_rows($res);
+  $f = serveur_defini('spip_' . $serveur . '_count', $serveur);
+  return $f($res);
+}
+
+function spip_abstract_free($res, $serveur='')
+{
+  if (!$serveur) return spip_free_result($res);
+  $f = serveur_defini('spip_' . $serveur . '_free', $serveur);
+  return $f($res);
+}
 ?>
diff --git a/inc-compilo-index.php3 b/inc-compilo-index.php3
index 2108454e467096909441314762f8051ca8b7accd..2978e78ce02631c6a85aec55bd9ffaa75299d5ce 100644
--- a/inc-compilo-index.php3
+++ b/inc-compilo-index.php3
@@ -29,6 +29,7 @@ class Boucle {
 	var $cond_avant, $milieu, $cond_apres, $cond_altern;
 	var $lang_select;
 	var $type_requete;
+	var $sql_serveur;
 	var $param;
 	var $separateur;
 	var $doublons;
@@ -108,7 +109,7 @@ function index_pile($idb, $nom_champ, &$boucles, $explicite='') {
 		$desc = $tables_principales[$t];
 		if (!$desc) {
 			include_local("inc-admin.php3");
-			erreur_squelette(_L("Table SQL $r absente de \$tables_principales dans inc_serialbase"), "'$idb'");
+			erreur_squelette(_L("Table SQL \"$r\" absente de \$tables_principales dans inc_serialbase"), "'$idb'");
 		}
 		$excep = $exceptions_des_tables[$r][$c];
 		if ($excep) {
diff --git a/inc-compilo.php3 b/inc-compilo.php3
index d0be9a42836e6a46420da8d3750f62782f628b1e..b5035d9504432233d15da4a06de4f4b0c4346a3a 100644
--- a/inc-compilo.php3
+++ b/inc-compilo.php3
@@ -39,7 +39,6 @@ include_ecrire('inc_serialbase.php3');
 // outils pour debugguer le compilateur
 #include_local("inc-compilo-debug.php3"); # desactive
 
-
 //
 // Calculer un <INCLURE()>
 //
@@ -146,7 +145,9 @@ function calculer_boucle($id_boucle, &$boucles) {
 	if ($type_boucle == 'boucle')
 	    return ("\n	return $return;");
 
-	// Cas general : appeler la fonction de definition de la boucle
+	// Toute autre boucle
+	
+	// appeler la fonction de definition de la boucle
 	$f = 'boucle_'.strtoupper($type_boucle);	// definition perso
 	if (!function_exists($f)) $f = $f.'_dist';			// definition spip
 	if (!function_exists($f)) $f = 'boucle_DEFAUT';		// definition par defaut
@@ -172,7 +173,7 @@ function calculer_boucle($id_boucle, &$boucles) {
 	if ($lang_select)
 		$boucle->select[] = 
 			// cas des tables SPIP
-			(($id_table = $table_des_tables[$type_boucle]) ? $id_table.'.' : '')
+			($id_table ? $id_table.'.' : '')
 			// cas general ({lang_select} sur une table externe)
 			. 'lang';
 
@@ -180,7 +181,8 @@ function calculer_boucle($id_boucle, &$boucles) {
 	$primary_key = $table_primary[$type_boucle];
 
 	// Calculer les invalideurs si c'est une boucle non constante
-	$constant = ereg("^'[^']*'$",$return);
+	$constant = ereg("^\(?'[^']*'\)?$",$return);
+
 	if ((!$primary_key) || $constant)
 		$invalide = '';
 	else {
@@ -201,6 +203,7 @@ function calculer_boucle($id_boucle, &$boucles) {
 	}
 
 	// Cas {1/3} {1,4} {n-2,1}...
+
 	$flag_cpt = $boucle->mode_partie || // pas '$compteur' a cause du cas 0
 		strpos($return,'compteur_boucle');
 
@@ -209,45 +212,57 @@ function calculer_boucle($id_boucle, &$boucles) {
 	//
 	$debut = '';
 	if ($flag_cpt)
-		$debut .= "\n		\$compteur_boucle++;";
+		$debut = "\n		\$compteur_boucle++;";
 
 	if ($boucle->mode_partie)
 		$debut .= '
 		if ($compteur_boucle-1 >= $debut_boucle
 		AND $compteur_boucle-1 <= $fin_boucle) {';
-
+	
 	if ($lang_select AND !$constant)
 		$debut .= '
 			if ($x = $Pile[$SP]["lang"]) $GLOBALS[\'spip_lang\'] = $x; // lang_select';
 
-	$corps = $debut . $invalide;
+	$debut .= $invalide;
 
 	if ($boucle->doublons)
-		$corps .= "\n			\$doublons['".$boucle->doublons."'] .= ','. " .
+		$debut .= "\n			\$doublons['".$boucle->doublons."'] .= ','. " .
 		index_pile($id_boucle, $primary_key, $boucles)
 		. "; // doublons";
 
-
-	//
-	// L'ajouter au corps
-	//
-	// Separateur ?
-	if ($boucle->separateur) {
-		$corps .= "\n			\$t1 = $return;
-		\$t0 .= ((\$t1 && \$t0) ? '"
-		. $boucle->separateur
-		. "' : '')
-		. \$t1;";
-	} else if ($constant && !$debut) {
-		$corps .= $return;
-	} else {
-		$corps .= "\n			\$t0 .= $return;";
-	}
-
+	// gestion optimale des separateurs et des boucles constantes
+
+	$corps = $debut . 
+		((!$boucle->separateur) ? 
+			(($constant && !$debut) ? $return :
+			 	("\n\t\t" . '$t0 .= ' . $return . ";")) :
+		 ("\n\t\t\$t1 " .
+			((strpos($return, '$t1.') === 0) ? 
+			 (".=" . substr($return,4)) :
+			 ('= ' . $return)) .
+		  ";\n\t\t" .
+		  '$t0 .= (($t1 && $t0) ? \'' . $boucle->separateur .
+		  "' : '') . \$t1;"));
+     
 	// Fin de parties
 	if ($boucle->mode_partie)
 		$corps .= "\n		}\n";
 
+	// si le corps est une constante, ne pas appeler le serveur N fois!
+	if (ereg("^\(?'[^']*'\)?$",$corps)) {
+		// vide ?
+		if (($corps == "''") || ($corps == "('')")) {
+			if (!$boucle->numrows)
+				return 'return "";';
+			else
+				$corps = "";
+		} else {
+			$boucle->numrows = true;
+			$corps = "\n		".'for($x=$Numrows["'.$id_boucle.'"];$x>0;$x--)
+			$t0 .= ' . $corps .';';
+		}
+		$texte = '';
+	} else {
 
 	// Gestion de la hierarchie (voir inc-boucles.php3)
 	if ($boucle->hierarchie)
@@ -259,25 +274,13 @@ function calculer_boucle($id_boucle, &$boucles) {
 	// RECHERCHE
 	list($hash_recherche, $hash_recherche_strict) = requete_hash($GLOBALS["recherche"]);';
 	}
-
-	// si le corps est une constante, ne plus appeler le serveur
-	if (ereg("^'[^']*'$",$corps)) {
-		// vide ?
-		if ($corps == "''") {
-			if (!$boucle->numrows)
-				return 'return "";';
-			else
-				$corps = "";
-		} else {
-			$boucle->numrows = true;
-			$corps = "\n		".'for($x=$Numrows["'.$id_boucle.'"];$x>0;$x--)
-			$t0 .= ' . $corps .';';
-	    }
-	} else {
 		$corps = '
 
 	// RESULTATS
-	while ($Pile[$SP] = @spip_fetch_array($result)) {'. "\n$corps\n	}\n";
+	while ($Pile[$SP] = @spip_abstract_fetch($result,"' .
+		  $boucle->sql_serveur .
+		  '")) {'. "\n$corps\n	}\n";
+		 
 
 		// Memoriser la langue avant la boucle pour la restituer apres
 		if ($lang_select) {
@@ -298,12 +301,14 @@ function calculer_boucle($id_boucle, &$boucles) {
 	$init .= "\$result = ";
 
 
-	// En absence de champ c'est un decompte : on prend la primary pour
-	// avoir qqch (le marteau-pilon * est trop couteux, et le COUNT
-	// incompatible avec le cas general)
+	// En absence de champ c'est un decompte : 
+	// on prend la primary pour avoir qqch
+	// car le COUNT incompatible avec le cas general
+	// pour les tables sans primary, prendre * mais faudrait trouver mieux
 	$init .= "spip_abstract_select(\n\t\tarray(\"". 
-		((!$boucle->select) ? $id_field :
-		join("\",\n\t\t\"", array_unique($boucle->select))) .
+		(($boucle->select) ? 
+			join("\",\n\t\t\"", array_unique($boucle->select)) :
+			((strlen($id_field) > 1) ? $id_field : '*')) .
 		'"), # SELECT
 		array("' .
 		join('","', array_unique($boucle->from)) .
@@ -320,27 +325,32 @@ function calculer_boucle($id_boucle, &$boucles) {
 		'".$boucle->sous_requete."', # sous
 		".$boucle->compte_requete.", # compte
 		'".$id_table."', # table
-		'".$boucle->id_boucle."'); # boucle";
-
+		'".$boucle->id_boucle."', # boucle
+		'".$boucle->sql_serveur."'); # serveur";
 
 	$init .= "\n	".'$t0 = "";
 	$SP++;';
 	if ($flag_cpt)
 		$init .= "\n	\$compteur_boucle = 0;";
 
-	$boucle->mode_partie.$boucle->partie.$boucle->total_parties."  ";
+
 	if ($boucle->mode_partie)
 		$init .= calculer_parties($boucle->partie,
 			$boucle->mode_partie,
 			$boucle->total_parties,
 			$id_boucle);
 	else if ($boucle->numrows)
-		$init .= "\n	\$Numrows['$id_boucle'] = @spip_num_rows(\$result);";
+		$init .= "\n	\$Numrows['" .
+			$id_boucle .
+			"'] = @spip_abstract_count(\$result,'" .
+			$boucle->sql_serveur .
+			"');";
 
 	//
 	// Conclusion et retour
 	//
-	$conclusion = "\n	@spip_free_result(\$result);";
+	$conclusion = "\n	@spip_abstract_free(\$result,'" .
+	  $boucle->sql_serveur . "');";
 
 	return $texte . $init . $corps . $conclusion;
 }
@@ -358,8 +368,10 @@ function calculer_parties($partie, $mode_partie, $total_parties, $id_boucle) {
 	// n-1 pour le dernier ; donc total_boucle = 1 + debut - fin
 
 	// nombre total avant partition
-	$retour = "\n\n	// Partition\n	"
-	.'$nombre_boucle = @spip_num_rows($result);';
+	$retour = "\n\n	// Partition\n	" .
+		'$nombre_boucle = @spip_abstract_count($result,"' .
+		$boucle->sql_serveur .
+		'");';
 
 	ereg("([+-/])([+-/])?", $mode_partie, $regs);
 	list(,$op1,$op2) = $regs;
@@ -405,12 +417,6 @@ function calculer_parties($partie, $mode_partie, $total_parties, $id_boucle) {
 	return $retour;
 }
 
-function nom_de_fonction($nom)
-{
-  return 'BOUCLE' . ereg_replace("-","_", $nom) . '_';
-}
-
-
 // Production du code PHP a partir de la sequence livree par le phraseur
 // $boucles est passe par reference pour affectation par index_pile.
 // Retourne une expression PHP,
@@ -519,7 +525,9 @@ function calculer_squelette($squelette, $nom, $gram, $sourcefile) {
 	// pour le moment: "html" seul connu (HTML+balises BOUCLE)
 	$boucles = '';
 	spip_timer('calcul_skel');
+
 	include_local("inc-$gram-squel.php3");
+
 	$racine = parser($squelette, '',$boucles, $nom);
 #	include_local('inc-compilo-debug.php3');
 #	 afftable($racine);
@@ -654,8 +662,9 @@ function $nom (\$Cache, \$Pile, \$doublons=array(), \$Numrows='', \$SP=0) {
 
 	if ($GLOBALS['var_debug'])
 		squelette_debug_compile($nom, $sourcefile, $squelette_compile);
-
+#	spip_log($squelette_compile);
 	return $squelette_compile;
+
 }
 
 ?>
diff --git a/lagaffe.php3 b/lagaffe.php3
index df247d9c51f53f59f045bbe39ad9ff9c1bf6b449..0c706f8be1069da63c7f5e0b9f5234dc27e6c726 100644
--- a/lagaffe.php3
+++ b/lagaffe.php3
@@ -111,11 +111,12 @@ foreach($table_des_tables as $k => $v)
 }
 
 $fond = "lagaffe";
-if (!($f = fopen($GLOBALS['dossier_squelettes'] . $fond. ".html",'w')))
+$nom = $GLOBALS['dossier_squelettes'] . $fond. ".html";
+if (!($f = fopen($nom, 'w')))
   {if (function_exists("php_sapi_name")  AND eregi("cgi", @php_sapi_name()))
       Header("Status: 503");
     else Header("HTTP/1.0 Service Unavailable");
-    echo ("impossible d'écrire le fichier de tests");
+    echo ("impossible d'écrire le fichier de tests $nom");
     exit;
   }
 fwrite($f, $res);