Valider f16822d1 rédigé par cerdic's avatar cerdic
Parcourir les fichiers

Résoud #2260 :

Une boucle MOTS avec critere {id_objet} etait compilée de façon erronée en raison de plusieurs laxismes :
- on cherchait un champ id_objet dans une table de liaison candidate, la premiere etant dans ce cas spip_auteurs_liens, sans tenir compte de la plausabilité de la jointure, qui se faisait ensuite sur id_objet=id_mot AND objet='mot' ce qui n'a ici aucun sens
 => on corrige en cherchant table par table le champ cible ET la jointures possibles jusqu'a ce qu'on ait les deux qui vont bien
  
- on acceptait de créer ensuite une jointure en plusieurs étapes pour aller à cette table, alors qu'on sait dès le départ que c'est une jointure à une étape 
  => on permet de preciser dès l'appel de calculer_jointure() le nombre maximum d'étapes
  
- la jointure en plusieurs étapes se faisait parce que la gestion des tables vues et des milieux exclus 
 - acceptait de passer deux fois par la table d'arrivée => on corrige
 - pouvait ne pas reconnaitre la table d'arrivée qui contenait un coup le prefixe spip_ et un coup non => on double le test
 - acceptait de faire une jointure intermediaire sur la même clé qu'à l'arrivée (id_objet ici) => on interdit ce cas idiot
 - faisait une jointure sur objet en second lieu alors qu'on avait deja une jointure sur id_objet => on ajoute ce cas particulier

Ces correctifs ne devraient pas impacter les autres calculs de jointure, mais eviter d'autres cas tordus erronés comme celui là.
parent efcdd393
Chargement en cours
Chargement en cours
Chargement en cours
Chargement en cours
+22 −18
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -1205,12 +1205,11 @@ function calculer_critere_externe_init(&$boucle, $joints, $col, $desc, $cond, $c
		if ($res = calculer_lien_externe_init($boucle, $joints, $col, $desc, $cond, $checkarrivee))
			return $res;
	}

	$cle = trouver_champ_exterieur($col, $joints, $boucle, $checkarrivee);
	if (!$cle) return '';
	$t = array_search($cle[0], $boucle->from);
	foreach($joints as $joint){
		if ($arrivee = trouver_champ_exterieur($col, array($joint), $boucle, $checkarrivee)){
			$t = array_search($arrivee[0], $boucle->from);
			// transformer eventuellement id_xx en (id_objet,objet)
	$cols = trouver_champs_decomposes($col,$cle[1]);
			$cols = trouver_champs_decomposes($col,$arrivee[1]);
			if ($t) {
					$joindre = false;
					foreach($cols as $col){
@@ -1224,7 +1223,12 @@ function calculer_critere_externe_init(&$boucle, $joints, $col, $desc, $cond, $c
					}
					if (!$joindre) return $t;
			}
	return calculer_jointure($boucle, array($boucle->id_table, $desc), $cle, $cols, $cond);
			if ($res = calculer_jointure($boucle, array($boucle->id_table, $desc), $arrivee, $cols, $cond, 1))
				return $res;
		}
	}
	return '';

}

/**
+26 −12
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -76,15 +76,16 @@ function trouver_champs_decomposes($champ, $desc){
 * @param bool $cond
 * @return string
 */
function calculer_jointure(&$boucle, $depart, $arrivee, $col = '', $cond = false){
function calculer_jointure(&$boucle, $depart, $arrivee, $col = '', $cond = false, $max_liens=5){
	// les jointures minimales sont optimales :
	// on contraint le nombre d'etapes en l'augmentant
	// jusqu'a ce qu'on trouve une jointure ou qu'on atteigne la limite maxi 
	$max_liens = 1;
	$max = 1;
	$res = false;
	while ($max_liens<=5 AND !$res){
		$res = calculer_chaine_jointures($boucle, $depart, $arrivee, array(), array(), $max_liens);
		$max_liens++;
	$milieu_exclus = ($col?$col:array());
	while ($max<=$max_liens AND !$res){
		$res = calculer_chaine_jointures($boucle, $depart, $arrivee, array(), $milieu_exclus, $max);
		$max++;
	}
	if (!$res) return "";

@@ -289,11 +290,17 @@ function calculer_chaine_jointures(&$boucle, $depart, $arrivee, $vu = array(), $

	if (is_string($milieu_exclus))
		$milieu_exclus = array($milieu_exclus);
	// quand on a exclus id_objet comme cle de jointure, il faut aussi exclure objet
	// faire une jointure sur objet tout seul n'a pas de sens
	if (in_array('id_objet',$milieu_exclus) AND !in_array('objet',$milieu_exclus))
		$milieu_exclus[] = 'objet';

	list($dnom, $ddesc) = $depart;
	list($anom, $adesc) = $arrivee;
	if (!count($vu))
	if (!count($vu)){
		$vu[] = $dnom; // ne pas oublier la table de depart
		$vu[] = $anom; // ne pas oublier la table d'arrivee
	}

	$akeys = array();
	foreach ($adesc['key'] as $k)
@@ -347,8 +354,10 @@ function calculer_chaine_jointures(&$boucle, $depart, $arrivee, $vu = array(), $
	// sinon essayer de passer par une autre table
	$new = $vu;
	foreach ($boucle->jointures as $v){
		if ($v && (!in_array($v, $vu)) &&
		    ($def = $trouver_table($v, $boucle->sql_serveur))
		if ($v
		    AND !in_array($v, $vu)
		    AND $def = $trouver_table($v, $boucle->sql_serveur)
			  AND !in_array($def['table_sql'], $vu)
		){
			// ne pas tester les cles qui sont exclues a l'appel
			// ie la cle de la jointure precedente
@@ -359,13 +368,18 @@ function calculer_chaine_jointures(&$boucle, $depart, $arrivee, $vu = array(), $
			       AND $max_iter--){
				$jointure_directe_possible = reset($jointure_directe_possible);
				$milieu = end($jointure_directe_possible);
				if (is_string($milieu))
				$exclure_fin = $milieu_exclus;
				if (is_string($milieu)){
					$exclure_fin[] = $milieu;
					$test_cles[] = $milieu;
				else
				}
				else{
					$exclure_fin = array_merge($exclure_fin, $milieu);
					$test_cles = array_merge($test_cles, $milieu);
				}
				// essayer de rejoindre l'arrivee a partir de cette etape intermediaire
				// sans repasser par la meme cle milieu
				$r = calculer_chaine_jointures($boucle, array($v, $def), $arrivee, $new, $milieu, $max_liens-1);
				// sans repasser par la meme cle milieu, ni une cle deja vue !
				$r = calculer_chaine_jointures($boucle, array($v, $def), $arrivee, $new, $exclure_fin, $max_liens-1);
				if ($r){
					array_unshift($r, $jointure_directe_possible);
					return $r;