Exemple #1
0
/**
 * Gestion des requêtes ALTER non reconnues de SQLite
 *
 * Requêtes non reconnues :
 *
 *     ALTER TABLE table DROP column
 *     ALTER TABLE table CHANGE [COLUMN] columnA columnB definition
 *     ALTER TABLE table MODIFY column definition
 *     ALTER TABLE table ADD|DROP PRIMARY KEY
 *
 * `MODIFY` est transformé en `CHANGE columnA columnA` par spip_sqlite_alter()
 *
 * 1) Créer une table B avec le nouveau format souhaité
 * 2) Copier la table d'origine A vers B
 * 3) Supprimer la table A
 * 4) Renommer la table B en A
 * 5) Remettre les index (qui sont supprimés avec la table A)
 *
 * @param string|array $table
 *     - string : Nom de la table table,
 *     - array : couple (nom de la table => nom futur)
 * @param string|array $colonne
 *     - string : nom de la colonne,
 *     - array : couple (nom de la colonne => nom futur)
 * @param array $opt
 *     options comme les tables SPIP, qui sera mergé à la table créee :
 *     `array('field'=>array('nom'=>'syntaxe', ...), 'key'=>array('KEY nom'=>'colonne', ...))`
 * @param string $serveur
 *     Nom de la connexion SQL en cours
 * @return bool
 *     true si OK, false sinon.
 */
function _sqlite_modifier_table($table, $colonne, $opt = array(), $serveur = '')
{
    if (is_array($table)) {
        reset($table);
        list($table_origine, $table_destination) = each($table);
    } else {
        $table_origine = $table_destination = $table;
    }
    // ne prend actuellement qu'un changement
    // mais pourra etre adapte pour changer plus qu'une colonne a la fois
    if (is_array($colonne)) {
        reset($colonne);
        list($colonne_origine, $colonne_destination) = each($colonne);
    } else {
        $colonne_origine = $colonne_destination = $colonne;
    }
    if (!isset($opt['field'])) {
        $opt['field'] = array();
    }
    if (!isset($opt['key'])) {
        $opt['key'] = array();
    }
    // si les noms de tables sont differents, pas besoin de table temporaire
    // on prendra directement le nom de la future table
    $meme_table = $table_origine == $table_destination;
    $def_origine = sql_showtable($table_origine, false, $serveur);
    if (!$def_origine or !isset($def_origine['field'])) {
        spip_log("Alter table impossible sur {$table_origine} : table non trouvee", 'sqlite' . _LOG_ERREUR);
        return false;
    }
    $table_tmp = $table_origine . '_tmp';
    // 1) creer une table temporaire avec les modifications
    // - DROP : suppression de la colonne
    // - CHANGE : modification de la colonne
    // (foreach pour conserver l'ordre des champs)
    // field
    $fields = array();
    // pour le INSERT INTO plus loin
    // stocker la correspondance nouvelles->anciennes colonnes
    $fields_correspondances = array();
    foreach ($def_origine['field'] as $c => $d) {
        if ($colonne_origine && $c == $colonne_origine) {
            // si pas DROP
            if ($colonne_destination) {
                $fields[$colonne_destination] = $opt['field'][$colonne_destination];
                $fields_correspondances[$colonne_destination] = $c;
            }
        } else {
            $fields[$c] = $d;
            $fields_correspondances[$c] = $c;
        }
    }
    // cas de ADD sqlite2 (ajout du champ en fin de table):
    if (!$colonne_origine && $colonne_destination) {
        $fields[$colonne_destination] = $opt['field'][$colonne_destination];
    }
    // key...
    $keys = array();
    foreach ($def_origine['key'] as $c => $d) {
        $c = str_replace($colonne_origine, $colonne_destination, $c);
        $d = str_replace($colonne_origine, $colonne_destination, $d);
        // seulement si on ne supprime pas la colonne !
        if ($d) {
            $keys[$c] = $d;
        }
    }
    // autres keys, on merge
    $keys = array_merge($keys, $opt['key']);
    $queries = array();
    // copier dans destination (si differente de origine), sinon tmp
    $table_copie = $meme_table ? $table_tmp : $table_destination;
    $autoinc = (isset($keys['PRIMARY KEY']) and $keys['PRIMARY KEY'] and stripos($keys['PRIMARY KEY'], ',') === false and stripos($fields[$keys['PRIMARY KEY']], 'default') === false);
    if ($q = _sqlite_requete_create($table_copie, $fields, $keys, $autoinc, $temporary = false, $ifnotexists = true, $serveur)) {
        $queries[] = $q;
    }
    // 2) y copier les champs qui vont bien
    $champs_dest = join(', ', array_keys($fields_correspondances));
    $champs_ori = join(', ', $fields_correspondances);
    $queries[] = "INSERT INTO {$table_copie} ({$champs_dest}) SELECT {$champs_ori} FROM {$table_origine}";
    // 3) supprimer la table d'origine
    $queries[] = "DROP TABLE {$table_origine}";
    // 4) renommer la table temporaire
    // avec le nom de la table destination
    // si necessaire
    if ($meme_table) {
        if (_sqlite_is_version(3, '', $serveur)) {
            $queries[] = "ALTER TABLE {$table_copie} RENAME TO {$table_destination}";
        } else {
            $queries[] = _sqlite_requete_create($table_destination, $fields, $keys, $autoinc, $temporary = false, $ifnotexists = false, $serveur);
            $queries[] = "INSERT INTO {$table_destination} SELECT * FROM {$table_copie}";
            $queries[] = "DROP TABLE {$table_copie}";
        }
    }
    // 5) remettre les index !
    foreach ($keys as $k => $v) {
        if ($k == 'PRIMARY KEY') {
        } else {
            // enlever KEY
            $k = substr($k, 4);
            $queries[] = "CREATE INDEX {$table_destination}" . "_{$k} ON {$table_destination} ({$v})";
        }
    }
    if (count($queries)) {
        spip_sqlite::demarrer_transaction($serveur);
        // il faut les faire une par une car $query = join('; ', $queries).";"; ne fonctionne pas
        foreach ($queries as $q) {
            if (!spip_sqlite::executer_requete($q, $serveur)) {
                spip_log(_LOG_GRAVITE_ERREUR, "SQLite : ALTER TABLE table :" . " Erreur a l'execution de la requete : {$q}", 'sqlite');
                spip_sqlite::annuler_transaction($serveur);
                return false;
            }
        }
        spip_sqlite::finir_transaction($serveur);
    }
    return true;
}
Exemple #2
0
function _sqlite_modifier_table($table, $colonne, $opt=array(), $serveur=''){

	if (is_array($table)) {
		reset($table);
		list($table_origine,$table_destination) = each($table);
	} else {
		$table_origine = $table_destination = $table;
	}
	// ne prend actuellement qu'un changement
	// mais pourra etre adapte pour changer plus qu'une colonne a la fois
	if (is_array($colonne)) {
		reset($colonne);
		list($colonne_origine,$colonne_destination) = each($colonne);
	} else {
		$colonne_origine = $colonne_destination = $colonne;
	}	
	if (!isset($opt['field'])) $opt['field'] = array();
	if (!isset($opt['key'])) $opt['key'] = array();
	
	// si les noms de tables sont differents, pas besoin de table temporaire
	// on prendra directement le nom de la future table
	$meme_table = ($table_origine == $table_destination);
	
	$def_origine = sql_showtable($table_origine, false, $serveur);
	$table_tmp = $table_origine . '_tmp';

	// 1) creer une table temporaire avec les modifications	
	// - DROP : suppression de la colonne
	// - CHANGE : modification de la colonne
	// (foreach pour conserver l'ordre des champs)
	
	// field 
	$fields = array();
	// pour le INSERT INTO plus loin
	// stocker la correspondance nouvelles->anciennes colonnes
	$fields_correspondances = array(); 
	foreach ($def_origine['field'] as $c=>$d){

		if ($colonne_origine && ($c == $colonne_origine)) {
			// si pas DROP
			if ($colonne_destination){
				$fields[$colonne_destination] = $opt['field'][$colonne_destination];
				$fields_correspondances[$colonne_destination] = $c;
			}	
		} else {
			$fields[$c] = $d;
			$fields_correspondances[$c] = $c;
		}
	}
	// cas de ADD sqlite2 (ajout du champ en fin de table):
	if (!$colonne_origine && $colonne_destination){
			$fields[$colonne_destination] = $opt['field'][$colonne_destination];
	}
	
	// key...
	$keys = array();
	foreach ($def_origine['key'] as $c=>$d){
		$c = str_replace($colonne_origine,$colonne_destination,$c);
		$d = str_replace($colonne_origine,$colonne_destination,$d);
		// seulement si on ne supprime pas la colonne !
		if ($d)
			$keys[$c] = $d;
	}

	// autres keys, on merge
	$keys = array_merge($keys,$opt['key']);
	$queries = array();
	$queries[] = 'BEGIN TRANSACTION';
	
	// copier dans destination (si differente de origine), sinon tmp
	$table_copie = ($meme_table) ? $table_tmp : $table_destination;
	
	if ($q = _sqlite_requete_create(
			$table_copie, 
			$fields, 
			$keys, 
			$autoinc=false,
			$temporary=false, 
			$ifnotexists=true,
			$serveur)){
		$queries[] = $q;			
	}

	
	// 2) y copier les champs qui vont bien
	$champs_dest = join(', ', array_keys($fields_correspondances));
	$champs_ori = join(', ', $fields_correspondances);
	$queries[] = "INSERT INTO $table_copie ($champs_dest) SELECT $champs_ori FROM $table_origine";
		
	// 3) supprimer la table d'origine
	$queries[] = "DROP TABLE $table_origine";
	
	// 4) renommer la table temporaire 
	// avec le nom de la table destination
	// si necessaire
	if ($meme_table){
		if (_sqlite_is_version(3, '', $serveur)){
			$queries[] = "ALTER TABLE $table_copie RENAME TO $table_destination";
		} else {
			$queries[] = _sqlite_requete_create(
					$table_destination, 
					$fields, 
					$keys, 
					$autoinc=false,
					$temporary=false, 
					$ifnotexists=false, // la table existe puisqu'on est dans une transaction
					$serveur);	
			$queries[] = "INSERT INTO $table_destination SELECT * FROM $table_copie";		
			$queries[] = "DROP TABLE $table_copie";
		}
	}
	
	// 5) remettre les index !
	foreach ($keys as $k=>$v) {
		if ($k=='PRIMARY KEY'){}
		else {
			// enlever KEY
			$k = substr($k,4);
			$queries[] = "CREATE INDEX $table_destination"."_$k ON $table_destination ($v)";
		}
	}
	
	$queries[] = "COMMIT";
	

	// il faut les faire une par une car $query = join('; ', $queries).";"; ne fonctionne pas
	foreach ($queries as $q){
		$req = new sqlite_traiter_requete($q, $serveur);
		if (!$req->executer_requete()){	
			spip_log("SQLite : ALTER TABLE table :" 
			." Erreur a l'execution de la requete : $q",'sqlite'); 
			return false;
		}
	}

	return true;					
}