From d952f8088142acdb81a0a977a3bdffdb793a47e6 Mon Sep 17 00:00:00 2001
From: Cerdic <cedric@yterium.com>
Date: Fri, 1 Feb 2008 22:38:33 +0000
Subject: [PATCH] le petit cache de la recherche prend du galon et integre la
 base sql : - creation d'une table spip_recherches qui stockent les resultats
 par id/points pour chaque recherche - les requetes decriees par #1231 et
 consort disparaissent au profit d'une simple jointure

La portabilite sql est a verifier pour cause :
- d'une fonction HEX() reliquat des vieilles version mysql
- dune jointure implicite ecrite en clause SELECT/WHERE dans le critere recherche
---
 ecrire/base/auxiliaires.php      | 12 +++++++
 ecrire/inc/prepare_recherche.php | 60 +++++++++++++-------------------
 ecrire/inc_version.php           |  3 +-
 ecrire/maj/svn10000.php          |  9 +++++
 ecrire/public/criteres.php       |  4 ++-
 5 files changed, 51 insertions(+), 37 deletions(-)

diff --git a/ecrire/base/auxiliaires.php b/ecrire/base/auxiliaires.php
index 54bf82d970..cc819f8cbb 100644
--- a/ecrire/base/auxiliaires.php
+++ b/ecrire/base/auxiliaires.php
@@ -42,6 +42,15 @@ $spip_visites_articles = array(
 $spip_visites_articles_key = array(
 		"PRIMARY KEY"	=> "date, id_article");
 
+$spip_recherches = array(
+ 		"recherche"	=> "BIGINT UNSIGNED NOT NULL",
+		"id"	=> "INT UNSIGNED NOT NULL",
+ 		"points"	=> "INT UNSIGNED DEFAULT '0' NOT NULL",
+		"maj"	=> "TIMESTAMP" );
+
+$spip_recherches_key = array(
+ 		"PRIMARY KEY"	=> "recherche,id");
+
 $spip_referers = array(
 		"referer_md5"	=> "bigint UNSIGNED NOT NULL",
 		"date"		=> "DATE NOT NULL",
@@ -272,6 +281,9 @@ $tables_auxiliaires['spip_mots_documents'] = array(
 $tables_auxiliaires['spip_meta'] = array(
 	'field' => &$spip_meta,
 	'key' => &$spip_meta_key);
+$tables_auxiliaires['spip_recherches'] = array(
+	'field' => &$spip_recherches,
+	'key' => &$spip_recherches_key);
 $tables_auxiliaires['spip_versions'] = array(
 	'field' => &$spip_versions,
 	'key' => &$spip_versions_key);
diff --git a/ecrire/inc/prepare_recherche.php b/ecrire/inc/prepare_recherche.php
index 35665c35c3..913fc1e4fb 100644
--- a/ecrire/inc/prepare_recherche.php
+++ b/ecrire/inc/prepare_recherche.php
@@ -14,13 +14,13 @@
 if (!defined("_ECRIRE_INC_VERSION")) return;
 
 include_spip('inc/rechercher');
+@define('_DELAI_CACHE_RECHERCHES',600);
 
 // Preparer les listes id_article IN (...) pour les parties WHERE
 // et points =  des requetes du moteur de recherche
 // http://doc.spip.org/@inc_prepare_recherche_dist
 function inc_prepare_recherche_dist($recherche, $table='articles', $cond=false, $serveur='') {
 	static $cache = array();
-	static $fcache = array();
 
 	// si recherche n'est pas dans le contexte, on va prendre en globals
 	// ca permet de faire des inclure simple.
@@ -31,20 +31,22 @@ function inc_prepare_recherche_dist($recherche, $table='articles', $cond=false,
 	if ($cond AND !strlen($recherche))
 		return array("''" /* as points */, /* where */ '1');
 
+
+	$rechercher = false;
 	// Premier passage : chercher eventuel un cache des donnees sur le disque
-	if (!$cache[$recherche]['hash']) {
-		$dircache = sous_repertoire(_DIR_CACHE,'rech');
-		$fcache[$recherche] =
-			$dircache . substr(md5($recherche),0,10).'.txt';
-		if (lire_fichier($fcache[$recherche], $contenu))
-			$cache[$recherche] = @unserialize($contenu);
+	if (!isset($cache[$recherche][$table])){
+		$hash = md5($recherche . $table);
+		$res = sql_select('NOW()-maj AS fraicheur','spip_recherches',"recherche=0x$hash OR HEX(recherche)='$hash'",'','fraicheur DESC','0,1','',$serveur);
+		if ((!$row = sql_fetch($res))
+		 OR ($row['fraicheur']>_DELAI_CACHE_RECHERCHES)){
+		 	$rechercher = true;
+		}
+		$cache[$recherche][$table] = array("points","(recherche=0x$hash OR HEX(recherche)='$hash')");
 	}
 
-
 	// si on n'a pas encore traite les donnees dans une boucle precedente
-	if (!$cache[$recherche][$table]) {
-
-		$tables = liste_des_champs();
+	if ($rechercher) {
+		//$tables = liste_des_champs();
 		$x = preg_replace(',s$,', '', $table); // eurk
 		if ($x == 'syndic') $x = 'site';
 		$points = recherche_en_base($recherche,
@@ -67,31 +69,19 @@ function inc_prepare_recherche_dist($recherche, $table='articles', $cond=false,
 			$points = $p2;
 		}
 
-		# calculer le {id_article IN()} et le {... as points}
-		if (!count($points)) {
-			$cache[$recherche][$table] = array("''", '0');
-		} else {
-			$listes_ids = array();
-			$primary = id_table_objet($table);
-			foreach ($points as $id => $p)
-				$listes_ids[$p['score']] .= ','.$id;
-			$select = '';
-			foreach ($listes_ids as $p => $liste_ids)
-				$select .= "+ (case when (".
-			  sql_in("$table.$primary", substr($liste_ids, 1),'',$serveur)
-					.") then $p else 0 end) ";
-
-			$select = $select ? substr($select,1) : '0';
-			$cache[$recherche][$table] = array($select,
-				'('.sql_in("$table.$primary",
-					   array_keys($points),'',$serveur).')'
-				);
+		// supprimer les anciens resultats de cette recherche et les resultats trop vieux avec une marge
+		// hash=0x$hash OR HEX(hash)='$hash' permet d'avoir une requete qui marche qu'on soit en mysql <4.1 ou >4.1
+		// il y a des versions ou install de mysql ou il faut l'un ou l'autre selon le hash ... !
+		sql_delete('spip_recherches','(maj<NOW()-'.(_DELAI_CACHE_RECHERCHES+100).") OR (recherche=0x$hash OR HEX(recherche)='$hash')",$serveur);
+
+		// inserer les resultats dans la table de cache des recherches
+		if (count($points)){
+			$values = "";
+			foreach ($points as $id => $p){
+				$values.= ",(0x$hash,".intval($id).",".intval($p['score']).")";
+			}
+			sql_insert('spip_recherches',"(recherche,id,points)",substr($values,1),array(),$serveur);
 		}
-
-		// ecrire le cache de la recherche sur le disque
-		ecrire_fichier($fcache[$recherche], serialize($cache[$recherche]));
-		// purger le petit cache
-		nettoyer_petit_cache('rech', 300);
 	}
 
 	return $cache[$recherche][$table];
diff --git a/ecrire/inc_version.php b/ecrire/inc_version.php
index 7be9d096f5..75793e92f8 100644
--- a/ecrire/inc_version.php
+++ b/ecrire/inc_version.php
@@ -292,7 +292,8 @@ $liste_des_forums = array(
 // (= numero SVN de leur derniere modif cassant la compatibilite)
 $spip_version_code = 11169;
 // version de la base SQL (= numero SVN de sa derniere modif)
-$spip_version = 11171;
+$spip_version = 11172;
+
 // version de l'interface a la base
 $spip_sql_version = 1;
 
diff --git a/ecrire/maj/svn10000.php b/ecrire/maj/svn10000.php
index fbae401682..2c774ef775 100644
--- a/ecrire/maj/svn10000.php
+++ b/ecrire/maj/svn10000.php
@@ -23,4 +23,13 @@ $GLOBALS['maj'][10990] = array(array('upgrade_types_documents'));
 // Aller plus vite pour les vieilles versions en redeclarant une seule les doc
 unset($GLOBALS['maj'][10990]);
 $GLOBALS['maj'][11042] = array(array('upgrade_types_documents'));
+
+function maj_11172() {
+	global $tables_auxiliaires;
+	include_spip('base/auxiliaires');
+	$v = $tables_auxiliaires[$k='spip_recherches'];
+	sql_create($k, $v['field'], $v['key'], false, false);
+}
+$GLOBALS['maj'][11172] = array(array('maj_11172'));
+
 ?>
diff --git a/ecrire/public/criteres.php b/ecrire/public/criteres.php
index 093f844d1b..a5f5aef2bf 100644
--- a/ecrire/public/criteres.php
+++ b/ecrire/public/criteres.php
@@ -181,7 +181,9 @@ function critere_recherche_dist($idb, &$boucles, $crit) {
 	$t = $boucle->id_table . '.' . $boucle->primary;
 	if (!in_array($t, $boucles[$idb]->select))
 	  $boucle->select[]= $t; # pour postgres, neuneu ici
-	$boucle->select[]= '$rech_select as points';
+	$boucle->select[]= 'recherches.points as points';
+	$boucle->from[]= 'spip_recherches as `recherches`';
+	$boucle->where[]= "'recherches.id=".$boucle->id_table.".".$boucle->primary."'";
 
 	// et la recherche trouve
 	$boucle->where[]= '$rech_where';
-- 
GitLab