/** * Générer directement une jointure via une table de lien spip_xxx_liens * pour un critère {id_xxx} * * @todo $checkarrivee doit être obligatoire ici ? * * @param Boucle $boucle * Description de la boucle * @param array $joints * Liste de jointures possibles (ex: $boucle->jointures ou $boucle->jointures_explicites) * @param string $col * Colonne cible de la jointure * @param array $desc * Description de la table * @param bool $cond * Flag pour savoir si le critère est conditionnel ou non * @param bool|string $checkarrivee * string : nom de la table jointe où on veut trouver le champ. * n'a normalement pas d'appel sans $checkarrivee. * @return string * Alias de la table de jointure (Lx) */ function calculer_lien_externe_init(&$boucle, $joints, $col, $desc, $cond, $checkarrivee = false) { $primary_arrivee = id_table_objet($checkarrivee); // [FIXME] $checkarrivee peut-il arriver avec false ???? $intermediaire = trouver_champ_exterieur($primary_arrivee, $joints, $boucle, $checkarrivee . "_liens"); $arrivee = trouver_champ_exterieur($col, $joints, $boucle, $checkarrivee); if (!$intermediaire or !$arrivee) { return ''; } array_pop($intermediaire); // enlever la cle en 3eme argument array_pop($arrivee); // enlever la cle en 3eme argument $res = fabrique_jointures($boucle, array(array($boucle->id_table, $intermediaire, array(id_table_objet($desc['table_objet']), 'id_objet', 'objet', $desc['type'])), array(reset($intermediaire), $arrivee, $primary_arrivee)), $cond, $desc, $boucle->id_table, array($col)); return $res; }
function trouver_jointure_champ($champ, &$boucle) { $cle = trouver_champ_exterieur($champ, $boucle->jointures, $boucle); if ($cle) { $desc = $boucle->show; $cle = calculer_jointure($boucle, array($desc['id_table'], $desc), $cle, false); } if ($cle) return $cle; spip_log("trouver_jointure_champ: $champ inconnu"); return ''; }
function index_tables_en_pile($idb, $nom_champ, &$boucles) { global $exceptions_des_tables; $r = $boucles[$idb]->type_requete; if ($r == 'boucle') return array(); if (!$r) { # continuer pour chercher l'erreur suivante return array("'#" . $r . ':' . $nom_champ . "'",''); } $desc = $boucles[$idb]->show; $excep = isset($exceptions_des_tables[$r]) ? $exceptions_des_tables[$r] : ''; if ($excep) $excep = isset($excep[$nom_champ]) ? $excep[$nom_champ] : ''; if ($excep) { return index_exception($boucles[$idb], $desc, $nom_champ, $excep); } else { if (isset($desc['field'][$nom_champ])) { $t = $boucles[$idb]->id_table; return array("$t.$nom_champ", $nom_champ); } else { if ($boucles[$idb]->jointures_explicites) { $t = trouver_champ_exterieur($nom_champ, $boucles[$idb]->jointures, $boucles[$idb]); if ($t) return index_exception($boucles[$idb], $desc, $nom_champ, array($t[1]['id_table'], $nom_champ)); } return array('',''); } } }
function calculer_critere_externe_init(&$boucle, $joints, $col, $desc, $eg, $checkarrivee = false) { $cle = trouver_champ_exterieur($col, $joints, $boucle, $checkarrivee); if (!$cle) return ''; $t = array_search($cle[0], $boucle->from); // transformer eventuellement id_xx en (id_objet,objet) $cols = trouver_champs_decomposes($col,$cle[1]); if ($t) { $joindre = false; foreach($cols as $col){ $c = '/\b' . $t . ".$col" . '\b/'; if (trouver_champ($c, $boucle->where)) $joindre = true; else { // mais ca peut etre dans le FIELD pour le Having $c = "/FIELD.$t" .".$col,/"; if (trouver_champ($c, $boucle->select)) $joindre = true; } } if (!$joindre) return $t; } return calculer_jointure($boucle, array($boucle->id_table, $desc), $cle, $cols, $eg); }
/** * Generer directement une jointure via une table de lien spip_xxx_liens * pour un critere {id_xxx} * @param $boucle * @param $joints * @param $col * @param $desc * @param $cond * @param bool $checkarrivee * @return string */ function calculer_lien_externe_init(&$boucle, $joints, $col, $desc, $cond, $checkarrivee = false) { $primary_arrivee = id_table_objet($checkarrivee); $intermediaire = trouver_champ_exterieur($primary_arrivee, $joints, $boucle, $checkarrivee . "_liens"); $arrivee = trouver_champ_exterieur($col, $joints, $boucle, $checkarrivee); if (!$intermediaire or !$arrivee) { return ''; } $res = fabrique_jointures($boucle, array(array($boucle->id_table, $intermediaire, array(id_table_objet($desc['table_objet']), 'id_objet', 'objet', $desc['type'])), array(reset($intermediaire), $arrivee, $primary_arrivee)), $cond, $desc, $boucle->id_table, array($col)); return $res; }
/** * Cherche un champ dans une boucle * * Le champ peut être : * * - un alias d'un autre : il faut alors le calculer, éventuellement en * construisant une jointure. * - présent dans la table : on l'utilise * - absent, mais le type de boucle l'autorise (joker des itérateurs DATA) : * on l'utilise et lève le drapeau joker * - absent, on cherche une jointure et on l'utilise si on en trouve. * * @todo * Ici la recherche de jointure sur l'absence d'un champ ne cherche * une jointure que si des jointures explicites sont demandées, * et non comme à d'autres endroits sur toutes les jointures possibles. * Il faut homogénéiser cela. * * * @param string $idb Identifiant de la boucle * @param string $nom_champ Nom du champ SQL cherché * @param Boucle $boucles AST du squelette * @param bool $joker * Le champ peut-il être inconnu à la compilation ? * Ce drapeau sera levé si c'est le cas. * @return array * Liste (Nom du champ véritable, nom du champ demandé). * Le nom du champ véritable est une expression pour le SELECT de * la boucle tel que "rubriques.titre" ou "mots.titre AS titre_mot". * Les éléments de la liste sont vides si on ne trouve rien. **/ function index_tables_en_pile($idb, $nom_champ, &$boucles, &$joker) { global $exceptions_des_tables; $r = $boucles[$idb]->type_requete; // boucle recursive, c'est foutu... if ($r == TYPE_RECURSIF) { return array(); } if (!$r) { $joker = false; // indiquer a l'appelant # continuer pour chercher l'erreur suivante return array("'#" . $r . ':' . $nom_champ . "'", ''); } $desc = $boucles[$idb]->show; // le nom du champ est il une exception de la table ? un alias ? $excep = isset($exceptions_des_tables[$r]) ? $exceptions_des_tables[$r] : ''; if ($excep) { $excep = isset($excep[$nom_champ]) ? $excep[$nom_champ] : ''; } if ($excep) { $joker = false; // indiquer a l'appelant return index_exception($boucles[$idb], $desc, $nom_champ, $excep); } else { // le champ est réellement présent, on le prend. if (isset($desc['field'][$nom_champ])) { $t = $boucles[$idb]->id_table; $joker = false; // indiquer a l'appelant return array("{$t}.{$nom_champ}", $nom_champ); } elseif (isset($desc['field']['*'])) { $joker = true; // indiquer a l'appelant return array($nom_champ, $nom_champ); } else { $joker = false; // indiquer a l'appelant // regarder si le champ est deja dans une jointure existante // sinon, si il y a des joitures explicites, la construire if (!($t = trouver_champ_exterieur($nom_champ, $boucles[$idb]->from, $boucles[$idb]))) { if ($boucles[$idb]->jointures_explicites) { // [todo] Ne pas lancer que lorsque il y a des jointures explicites !!!! // fonctionnel, il suffit d'utiliser $boucles[$idb]->jointures au lieu de jointures_explicites // mais est-ce ce qu'on veut ? $jointures = preg_split("/\\s+/", $boucles[$idb]->jointures_explicites); if ($cle = trouver_jointure_champ($nom_champ, $boucles[$idb], $jointures)) { $t = trouver_champ_exterieur($nom_champ, $boucles[$idb]->from, $boucles[$idb]); } } } if ($t) { // si on a trouvé une jointure possible, on fait comme // si c'était une exception pour le champ demandé return index_exception($boucles[$idb], $desc, $nom_champ, array($t[1]['id_table'], reset($t[2]))); } return array('', ''); } } }
/** * Cherche un champ dans une boucle * * Le champ peut être : * - un alias d'un autre : il faut alors le calculer, éventuellement en * construisant une jointure. * - présent dans la table : on l'utilise * - absent, mais le type de boucle l'autorise (joker des itérateurs DATA) : * on l'utilise et lève le drapeau joker * - absent, on cherche une jointure et on l'utilise si on en trouve. * * @todo * Ici la recherche de jointure sur l'absence d'un champ ne cherche * une jointure que si des jointures explicites sont demandées, * et non comme à d'autres endroits sur toutes les jointures possibles. * Il faut homogénéiser cela. * * * @param string $idb Identifiant de la boucle * @param string $nom_champ Nom du champ SQL cherché * @param Boucle $boucles AST du squelette * @param bool $joker * Le champ peut-il être inconnu à la compilation ? * Ce drapeau sera levé si c'est le cas. * @return array * Liste (Nom du champ véritable, nom du champ demandé). * Le nom du champ véritable est une expression pour le SELECT de * la boucle tel que "rubriques.titre" ou "mots.titre AS titre_mot". * Les éléments de la liste sont vides si on ne trouve rien. **/ function index_tables_en_pile($idb, $nom_champ, &$boucles, &$joker) { global $exceptions_des_tables; $r = $boucles[$idb]->type_requete; // boucle recursive, c'est foutu... if ($r == TYPE_RECURSIF) { return array(); } if (!$r) { $joker = false; // indiquer a l'appelant # continuer pour chercher l'erreur suivante return array("'#" . $r . ':' . $nom_champ . "'", ''); } $desc = $boucles[$idb]->show; // le nom du champ est il une exception de la table ? un alias ? $excep = isset($exceptions_des_tables[$r]) ? $exceptions_des_tables[$r] : ''; if ($excep) { $excep = isset($excep[$nom_champ]) ? $excep[$nom_champ] : ''; } if ($excep) { $joker = false; // indiquer a l'appelant return index_exception($boucles[$idb], $desc, $nom_champ, $excep); } else { // le champ est réellement présent, on le prend. if (isset($desc['field'][$nom_champ])) { $t = $boucles[$idb]->id_table; $joker = false; // indiquer a l'appelant return array("{$t}.{$nom_champ}", $nom_champ); } elseif (isset($desc['field']['*'])) { $joker = true; // indiquer a l'appelant return array($nom_champ, $nom_champ); } else { $joker = false; // indiquer a l'appelant // [todo] Ne pas lancer que lorsque il y a des jointures explicites !!!! if ($boucles[$idb]->jointures_explicites) { $t = trouver_champ_exterieur($nom_champ, $boucles[$idb]->jointures, $boucles[$idb]); if ($t) { // si on a trouvé une jointure possible, on fait comme // si c'était une exception pour le champ demandé return index_exception($boucles[$idb], $desc, $nom_champ, array($t[1]['id_table'], $nom_champ)); } } return array('', ''); } } }
/** * Cherche a ajouter la possibilite d'interroger un champ sql * dans une boucle. Cela construira les jointures necessaires * si une possibilite est trouve et retournera le nom de * l'alias de la table contenant ce champ * (L2 par exemple pour 'spip_mots AS L2' dans le FROM), * * * @param string $champ * Nom du champ cherche (exemple id_article) * @param object $boucle * Informations connues de la boucle * @param array $jointures * Liste des tables parcourues (articles, mots) pour retrouver le champ sql * et calculer la jointure correspondante. * En son absence et par defaut, on utilise la liste des jointures connues * par SPIP pour la table en question ($boucle->jointures) * @param bool $cond * flag pour savoir si le critere est conditionnel ou non * * @return string */ function trouver_jointure_champ($champ, &$boucle, $jointures = false, $cond = false) { if ($jointures === false) { $jointures = $boucle->jointures; } $cle = trouver_champ_exterieur($champ, $jointures, $boucle); if ($cle) { $desc = $boucle->show; $cle = calculer_jointure($boucle, array($desc['id_table'], $desc), $cle, '', $cond); } if ($cle) { return $cle; } spip_log("trouver_jointure_champ: {$champ} inconnu"); return ''; }
/** * Cherche a ajouter la possibilite d'interroger un champ sql * dans une boucle. Cela construira les jointures necessaires * si une possibilite est trouve et retournera le nom de * l'alias de la table contenant ce champ * (L2 par exemple pour 'spip_mots AS L2' dans le FROM), * * * @param string $champ * Nom du champ cherche (exemple id_article) * @param object $boucle * Informations connues de la boucle * @param array $jointures * Liste des tables parcourues (articles, mots) pour retrouver le champ sql * et calculer la jointure correspondante. * En son absence et par defaut, on utilise la liste des jointures connues * par SPIP pour la table en question ($boucle->jointures) * @param bool $cond * flag pour savoir si le critere est conditionnel ou non * * @return string */ function trouver_jointure_champ($champ, &$boucle, $jointures = false, $cond = false) { if ($jointures === false) { $jointures = $boucle->jointures; } // TODO : aberration, on utilise $jointures pour trouver le champ // mais pas poour construire la jointure ensuite $arrivee = trouver_champ_exterieur($champ, $jointures, $boucle); if ($arrivee) { $desc = $boucle->show; array_pop($arrivee); // enlever la cle en 3eme argument $cle = calculer_jointure($boucle, array($desc['id_table'], $desc), $arrivee, '', $cond); if ($cle) { return $cle; } } spip_log("trouver_jointure_champ: {$champ} inconnu"); return ''; }