[spip-dev] [10863] mange le join...

Hello,
Jacques a constaté que [10863] cassait le plugtin AccesRestreint.

Après petite enquête, il semble que ca soit effectivement lié aux optimisations de calculer_select (composer.php)

si à une boucle, j'ajoute :
$boucle->where[] = '\'0=0\'';
(ce que produit une close NOT IN vide, c'est le cas pour accès restreint si l'utilisateur a droit à tout, mais le probleme se pose sans doute sans plugin avec des criteres {x IN #BALISE**})
ca met la pagaille dans les jointures parametrées :

Concrètement :

<BOUCLE_Rubrique(RUBRIQUES){id_rubrique}{type_mot=toto}>
produit :
05 $result = calculer_select(
06 array("rubriques.id_rubrique",
07 "rubriques.lang"), # SELECT
08 array('rubriques' => 'spip_rubriques','L1' => 'spip_mots_rubriques','L2' => 'spip_mots'), # FROM
09 10 array(
11 array('=', 'rubriques.id_rubrique', intval($Pile[0]['id_rubrique'])),
12 array('=', 'L2.type',
13 // 4 signes
14 "'toto'"),
15 array('=', 'rubriques.statut', '\'publie\'')), # WHERE
16 array(1 => array('rubriques', 'id_rubrique'), 2 => array('L1', 'id_mot')), # WHERE pour jointure
17 array('rubriques.id_rubrique'), # GROUP
18 array(), # ORDER
19 '', # LIMIT
20 21 array(), # HAVING
22 'rubriques', # table
23 '_Rubrique', # boucle
24 ''); # serveur
qui donne :
SELECT rubriques.id_rubrique, rubriques.lang FROM spip_rubriques AS `rubriques` INNER JOIN spip_mots_rubriques AS L1 ON rubriques.id_rubrique=L1.id_rubrique INNER JOIN spip_mots AS L2 ON L1.id_mot=L2.id_mot WHERE (rubriques.id_rubrique = 2) AND (L2.type = 'toto') AND (rubriques.statut = 'publie') GROUP BY rubriques.id_rubrique

Maintenant si je fais :
function boucle_RUBRIQUES($id_boucle, &$boucles) {
    $boucle = &$boucles[$id_boucle];
    $boucle->where[] = '\'0=0\'';
    return boucle_RUBRIQUES_dist($id_boucle, $boucles);
}

<BOUCLE_Rubrique(RUBRIQUES){id_rubrique}{type_mot=toto}>
produit bien :
$result = calculer_select(
06 array("rubriques.id_rubrique",
07 "rubriques.lang"), # SELECT
08 array('rubriques' => 'spip_rubriques','L1' => 'spip_mots_rubriques','L2' => 'spip_mots'), # FROM
09 10 array(
11 array('=', 'rubriques.id_rubrique', intval($Pile[0]['id_rubrique'])),
12 array('=', 'L2.type',
13 // 4 signes
14 "'toto'"), '0=0',
15 array('=', 'rubriques.statut', '\'publie\'')), # WHERE
16 array(1 => array('rubriques', 'id_rubrique'), 2 => array('L1', 'id_mot')), # WHERE pour jointure
17 array('rubriques.id_rubrique'), # GROUP
18 array(), # ORDER
19 '', # LIMIT
20 21 array(), # HAVING
22 'rubriques', # table
23 '_Rubrique', # boucle
24 ''); # serveur

qui donne par contre:
SELECT rubriques.id_rubrique, rubriques.lang FROM spip_rubriques AS `rubriques` INNER JOIN spip_mots AS L2 ON L1.id_mot=L2.id_mot WHERE (rubriques.id_rubrique = 2) AND (L2.type = 'toto') AND (rubriques.statut = 'publie') GROUP BY rubriques.id_rubrique

INNER JOIN spip_mots_rubriques AS L1 ON rubriques.id_rubrique=L1.id_rubrique a disparu !

La ca dépasse ma compréhension de la fonction calculer_select et du flag $menage en particulier.

Une piste ?

Sinon, je lis :
// IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)

si je dis pas de betise, il suffirait de modifier calculer_mysql_in :
function calcul_mysql_in($val, $valeurs, $not='') {
    if (is_array($valeurs))
        $valeurs = join(',', array_map('_q', $valeurs));
- if (!strlen(trim($valeurs))) return ($not ? "0=0" : '0=1');
+ if (!strlen(trim($valeurs))) return ($not ? 1 : '0=1');

mais la, c'est sans doute pas le moment de faire ce genre de choses...

@++

Hello,
Jacques a constaté que [10863] cassait le plugtin AccesRestreint.

Après petite enquête, il semble que ca soit effectivement lié aux
optimisations de calculer_select (composer.php)

....

INNER JOIN spip_mots_rubriques AS L1 ON
rubriques.id_rubrique=L1.id_rubrique a disparu !

La ca dépasse ma compréhension de la fonction calculer_select et du flag
$menage en particulier.

Une piste ?

Oui, vu. Le role de calculer_select est d'éliminer les jointures qui sont finalement inutiles car dépendant d'un critère conditionnel finalement inutilisé.
En remplaçant "From x,y WHERE X.truc = Y.truc" par "X INNER JOIN Y ON X.truc = Y.truc", j'ai oublié de mettre a jour calculer_select qui du coup ne voit pas que la jointure est nécessaire car "X.truc = Y.truc" a changé de place dans la structure de données.

Ca devrait se résoudre facilement mais
1. je suis charette, là
2. trac ne répond plus (il n'est pas le seul d'ailleurs).

Sinon, je lis :
// IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)

si je dis pas de betise, il suffirait de modifier calculer_mysql_in :
function calcul_mysql_in($val, $valeurs, $not='') {
    if (is_array($valeurs))
        $valeurs = join(',', array_map('_q', $valeurs));
- if (!strlen(trim($valeurs))) return ($not ? "0=0" : '0=1');
+ if (!strlen(trim($valeurs))) return ($not ? 1 : '0=1');

non non, rien à voir: "0=0" c'est "True" a la fois pour Mysql et PG car ils n'ont pas la même conception de la vérité.....

Committo,Ergo:Sum

Committo,Ergo:sum a écrit :

- if (!strlen(trim($valeurs))) return ($not ? "0=0" : '0=1');
+ if (!strlen(trim($valeurs))) return ($not ? 1 : '0=1');

non non, rien à voir: "0=0" c'est "True" a la fois pour Mysql et PG car ils n'ont pas la même conception de la vérité.....

?
C'est comme la différence entre un pigeon :
il a 2 pattes de la même taille, surtout la gauche !
JL

Committo,Ergo:sum a écrit :

Oui, vu. Le role de calculer_select est d'éliminer les jointures qui sont finalement inutiles car dépendant d'un critère conditionnel finalement inutilisé.
En remplaçant "From x,y WHERE X.truc = Y.truc" par "X INNER JOIN Y ON X.truc = Y.truc", j'ai oublié de mettre a jour calculer_select qui du coup ne voit pas que la jointure est nécessaire car "X.truc = Y.truc" a changé de place dans la structure de données.

Ca devrait se résoudre facilement mais
1. je suis charette, là
2. trac ne répond plus (il n'est pas le seul d'ailleurs).

OK, merci.

non non, rien à voir: "0=0" c'est "True" a la fois pour Mysql et PG car ils n'ont pas la même conception de la vérité.....

oui, ca j'ai compris, mais je n'ai pas été au bout de l'idée en fait.
l'idée c'est qu'un where puisse etre à true (0=0) ou à false (0=1) et que la compilation commence par chercher les false (pas besoin de calculer la requete si on sait qu'elle ne renverra rien) et eliminer les true.
Mais en fait, ca ne change pas grand chose, ca serait quand meme traité au meme niveau et pas à la compilation (le code serait peut etre plus clair et le debug plus facile ?).

@++

Committo,Ergo:sum a écrit :

Oui, vu. Le role de calculer_select est d'éliminer les jointures qui
sont finalement inutiles car dépendant d'un critère conditionnel
finalement inutilisé.
En remplaçant "From x,y WHERE X.truc = Y.truc" par "X INNER JOIN Y ON
X.truc = Y.truc", j'ai oublié de mettre a jour calculer_select qui du
coup ne voit pas que la jointure est nécessaire car "X.truc = Y.truc"
a changé de place dans la structure de données.

Bon, c'est réparé par 10909.

function calcul_mysql_in($val, $valeurs, $not='') {
    if (is_array($valeurs))
        $valeurs = join(',', array_map('_q', $valeurs));
- if (!strlen(trim($valeurs))) return ($not ? "0=0" : '0=1');
+ if (!strlen(trim($valeurs))) return ($not ? 1 : '0=1');

non non, rien à voir: "0=0" c'est "True" a la fois pour Mysql et PG
car ils n'ont pas la même conception de la vérité.....

oui, ca j'ai compris, mais je n'ai pas été au bout de l'idée en fait.
l'idée c'est qu'un where puisse etre à true (0=0) ou à false (0=1) et
que la compilation commence par chercher les false (pas besoin de
calculer la requete si on sait qu'elle ne renverra rien) et eliminer les
true.

oui, il faut remonter en amont dans le compilateur parce que là c'est une fonction spécifique au portage MysQL, alors que l'optimisation est valable pour tous les portages.

Committo,Ergo:Sum

Committo,Ergo:sum a écrit :

Committo,Ergo:sum a écrit :

Oui, vu. Le role de calculer_select est d'éliminer les jointures qui
sont finalement inutiles car dépendant d'un critère conditionnel
finalement inutilisé.
En remplaçant "From x,y WHERE X.truc = Y.truc" par "X INNER JOIN Y ON
X.truc = Y.truc", j'ai oublié de mettre a jour calculer_select qui du
coup ne voit pas que la jointure est nécessaire car "X.truc = Y.truc"
a changé de place dans la structure de données.

Bon, c'est réparé par 10909.

je confirme.
nickel, merci.

@++