Commit 83054a11 authored by Feu's avatar Feu

un grand coup de sqlrewriter

parent 3cab0139
......@@ -37,6 +37,8 @@ require_once($topdir."include/catalog.inc.php");
* rapide que sqltable v1 grâce à une meilleure implémentation. Même s'il est
* vrai que quelques pourcents pourraient être gagnés en enlevant les nouvelles
* fonctionalités.
*
* @author Julien Etelain
*/
class sqltable2 extends stdcontents
{
......@@ -390,7 +392,7 @@ class sqltable2 extends stdcontents
* @param $id_name Champ SQL contenant l'identifiant unique de chaque ligne
* @param $data Données : soit une objet requete, soit un tableau
*/
public function set_data ( $id_name, &$data )
public function set_data ( $id_name, &$data, $rewrited=false )
{
$this->id_name = $id_name;
......@@ -407,7 +409,7 @@ class sqltable2 extends stdcontents
// Support des fonctionalités asynchrone (tri et filtrage)
if ( isset($_REQUEST["sqltable2"]) && $_REQUEST["sqltable2"] == $this->nom )
if ( isset($_REQUEST["sqltable2"]) && $_REQUEST["sqltable2"] == $this->nom && !$rewrited )
{
if ( isset($_REQUEST["__st2f"]) && is_array($_REQUEST["__st2f"]) ) // SqlTable2Filter (fonctionne par champ sql!!)
{
......@@ -513,19 +515,65 @@ class sqltable2 extends stdcontents
* L'usage de cette fonction permet une meilleure implémentation des
* fonctionalités avancées de sqltable v2.
*
* Cette fonction pourra être amenée à ré-écrire votre requête
* (pour compter le nombre de lignes, pour insérer un LIMIT, modifier le
* ORDER BY, rajouter des conditions...)
*
* Cette fonction pourra être amenée à ré-écrire votre requête, elle doit donc
* respecter les contraintes de sqlrewriter.
* @param $db Lien à la base de donnée
* @param $id_name Champ SQL contenant l'identifiant unique de chaque ligne
* @param $sql Requête SQL
* @param $pagination Active la pagination automatique
* @param $npp Nombre de lignes par page
* @see sqlrewriter
*/
public function set_sql ( &$db, $id_name, $sql, $pagination=false, $npp=50 )
public function set_sql ( &$db, $id_name, $sql )
{
global $topdir;
if ( isset($_REQUEST["sqltable2"]) && $_REQUEST["sqltable2"] == $this->nom && !$rewrited )
{
require_once($topdir."include/sqlrewriter.inc.php");
$rewriter = new sqlrewriter($sql);
if ( isset($_REQUEST["__st2f"]) && is_array($_REQUEST["__st2f"]) ) // SqlTable2Filter (fonctionne par champ sql!!)
{
foreach ( $_REQUEST["__st2f"] as $field => $filter )
{
switch ( $filter{1} )
{
case "d" : $val = date('Y-m-d H:i:s',datetime_to_timestamp(substr($filter,2))); break:
case "m" : $val = get_prix(substr($filter,2)); break:
default : $val = substr($filter,2); break:
}
switch ( $filter{0} )
{
case "=" : $cond = "= '".mysql_real_escape_string($val)."'"; break;
case "l" : $cond = "LIKE '%".mysql_real_escape_string($val)."%'"; break;
case "!" : $cond = "!= '".mysql_real_escape_string($val)."'"; break;
case ">" : $cond = ">= '".mysql_real_escape_string($val)."'"; break;
case "<" : $cond = "<= '".mysql_real_escape_string($val)."'"; break;
}
$rewriter->add_condition($field,$cond);
}
}
if ( isset($_REQUEST["__st2s"]) && is_array($_REQUEST["__st2s"]) ) // SqlTable2Sorter (fonctionne par colonne!!)
{
//NOTE: les colonnes énumérées ne sont pas correctement supportées
$rewriter->reset_orderby();
foreach ( $_REQUEST["__st2s"] as $column => $sort )
{
$col = $this->columns[$column];
if ( count($col[2]) == 1 ) // cas d'une simple colonne
$rewriter->add_orderby($col[2][0],$sort{0}=="d"?'DESC':'ASC');
else
$rewriter->add_orderby('COLASCE('+implode(',',array_reverse($col[2]))+')',$sort{0}=="d"?'DESC':'ASC');
}
}
$this->set_data($id_name,new requete($db,$rewriter->get_sql(),true));
echo "<!-- ".$rewriter->get_sql()." -->";
return;
}
$this->set_data($id_name,new requete($db,$sql));
}
......
<?php
/* Copyright 2008
* - Julien Etelain < julien at pmad dot net >
*
* Ce fichier fait partie du site de l'Association des Étudiants de
* l'UTBM, http://ae.utbm.fr.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
/**
* Classe utilitaire pour la ré-écriture de requêtes SQL
*
* @author Julien Etelain
*/
class sqlrewriter
{
var $select='';
var $from='';
var $where='';
var $wherewrap=false;
var $groupby='';
var $having='';
var $havingwrap=false;
var $orderby='';
var $limit='';
var $fields=array();
/**
* Consrtuit un sqlrewrite en partant sur une requête SQL.
* Attention/ Ne fonctionne *que* pour les requêtes de selection !
*
* Decompose la requête de selection en ses principales composantes.
*
* Quelques limitations et contraintes :
* - Les mots clefs SQL DOIVENT être en majuscules et être entourés d'espaces :
* ' FROM ', ' WHERE ', ' GROUP BY ', ' HAVING ', ' LIMIT ', ' AS ' ... ;
* - Les champs calculé DOIVENT avoir des alias ;
* - Les sous-requêtes NE SONT PAS supportées.
*
* @param $sql requête SQL
*/
function sqlrewriter ( $sql )
{
$sql = str_replace('\n',' ',$sql); // Protection des requêtes insérées avec le coding style de pedrov
$ppos = $pos = stripos($sql, 'FROM ');
$this->select = substr($sql,0,$pos);
$pos = strpos($sql, 'WHERE ', $ppos);
if ( $pos !== false )
{
$this->from = substr($sql,$ppos,$pos-$ppos);
$ppos=$pos;
$p='where';
}
else
$p='from';
$pos = strpos($sql, 'GROUP BY ', $ppos);
if ( $pos !== false )
{
$this->$p = substr($sql,$ppos,$pos-$ppos);
$ppos=$pos;
$p='groupby';
}
$pos = strpos($sql, 'HAVING ', $ppos);
if ( $pos !== false )
{
$this->$p = substr($sql,$ppos,$pos-$ppos);
$ppos=$pos;
$p='having';
}
$pos = strpos($sql, 'ORDER BY ', $ppos);
if ( $pos !== false )
{
$this->$p = substr($sql,$ppos,$pos-$ppos);
$ppos=$pos;
$p='orderby';
}
$pos = strpos($sql, 'LIMIT ', $ppos);
if ( $pos !== false )
{
$this->$p = substr($sql,$ppos,$pos-$ppos);
$this->limit = substr($sql,$pos);
$ppos=$pos;
}
else
$this->$p = substr($sql,$ppos);
}
private function register_field($type,$nom)
{
$nom = trim(str_replace('`','',$nom));
$p = strpos($nom,'.');
if ( $p !== false )
{
$this->aliasfields[substr($nom,$p+1)] = array($type,$nom);
return;
}
$this->fields[$nom] = array($type,$nom);
}
/**
* Extraits les champs de la requête SQL et determine leur type (alias ou champ réel).
*
* L'ensemble des données sont positionnées dans $this->fields :
* nom du champ renvoyé par get_row() => array ( type, nom complet dans la requête ).
*
* Avec type =1 pour les alias, et type=0 pour les champs réels.
*/
function extract_fields()
{
$ppos=6;
$pos0=0;
$pos1=0;
do
{
$type=0;
$pos = strpos($this->select, ',', $ppos);
if ( $pos0 !== false && $pos0 < $ppos )
$pos0 = stripos($this->select, ' AS ', $ppos);
if ( $pos1 !== false && $pos1 < $ppos )
$pos1 = strpos($this->select, '(', $ppos);
if ( $pos !== false && (( $pos1 !== false && $pos1 < $pos) || ($pos0 !== false && $pos0 < $pos) ) )
{
$type=1;
$ppos = $pos0+4;
$pos = strpos($this->select, ',', $ppos);
}
if ( $pos !== false )
{
$this->register_field($type, substr($this->select,$ppos,$pos-$ppos));
$ppos = $pos+1;
}
else
{
$this->register_field($type, substr($this->select,$ppos));
$ppos = false;
}
}
while ( $ppos !== false );
}
/**
* Renvoie la requête SQL reconstruite
* @return la requête SQL
*/
function get_sql()
{
return $this->select.$this->from.$this->where.$this->groupby.
$this->having.$this->orderby.$this->limit;
}
function reset_orderby()
{
$this->orderby = '';
}
funtion add_orderby ( $nom, $o = 'ASC' )
{
if ( count($this->fields) == 0 )
$this->extract_fields();
if ( !isset($this->fields[$nom]) )
return false;
if ( empty($this->orderby) )
$this->orderby = 'ORDER BY '.$nom.' '.$o.' ';
else
$this->orderby = ', '.$nom.' '.$o.' ';
return true;
}
function add_condition ( $nom, $condition )
{
if ( count($this->fields) == 0 )
$this->extract_fields();
if ( !isset($this->fields[$nom]) )
return false;
$field = $this->fields[$nom];
if ( $field[0] == 1 ) // Alias => HAVING
{
if ( !$this->havingwrap )
{
if ( !empty($this->having ) )
$this->having = 'HAVING ('.substr($this->having,7).') AND ';
else
$this->having = 'HAVING ';
$this->havingwrap = true;
}
else
$this->having .= 'AND ';
$this->having .= $field[1].' '.$condition.' ';
return true;
}
if ( !$this->wherewrap )
{
if ( !empty($this->where ) )
$this->where = 'WHERE ('.substr($this->where,6).') AND ';
else
$this->where = 'WHERE ';
$this->wherewrap = true;
}
else
$this->where .= 'AND ';
$this->where .= $field[1].' '.$condition.' ';
return true;
}
function set_limit ( $start, $length )
{
$this->limit='LIMIT '.$start.','.$length;
}
}
?>
\ No newline at end of file
......@@ -10,7 +10,7 @@ $site->add_css("css/sqltable2.css");
$site->start_page("sas", "Test de sqltable2" );
$cts = new contents("table");
$req = new requete ( $site->db, "SELECT " .
$sql = "SELECT " .
"`cpta_operation`.`id_op`, " .
"`cpta_operation`.`num_op`, " .
"`cpta_operation`.`date_op`, " .
......@@ -51,7 +51,7 @@ $req = new requete ( $site->db, "SELECT " .
"LEFT JOIN `asso` AS `asso2` ON `cpta_cpasso`.`id_asso`=`asso2`.`id_asso` ".
"LEFT JOIN `cpta_cpbancaire` ON `cpta_cpasso`.`id_cptbc`=`cpta_cpbancaire`.`id_cptbc` ".
"WHERE `cpta_operation`.id_classeur='162' " .
"ORDER BY `cpta_operation`.`num_op` DESC" );
"ORDER BY `cpta_operation`.`num_op` DESC" ;
$tbl = new sqltable2("compte","Test","sqltable2.php");
......@@ -78,7 +78,7 @@ $tbl->set_column_isdiverse("commentaire_op");
$tbl->add_action("delete","Supprimer");
$tbl->add_action("print","Imprimer");
$tbl->set_data("id_op",$req);
$tbl->set_sql($site->db,"id_op",$sql);
$cts->add($tbl,true);
$site->add_contents($cts);
$site->end_page();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment