giovedì 27 novembre 2014

SQL DOCUMENTATION GENERATOR - VERSIONE 1.1.0.0

Dopo l'articolo riguardo la possibilità di inserire commenti ad elementi sql utilizzando le proprietà estese di SQL Server, è stato naturale pensare di inserire questa funzionalità nel progetto SQL Documentation Generator. Vediamo insieme le caratteristiche della versione 1.1.0.0 del nostro software.



Vi ricordo che potete trovare il file Jar di distribuzione nella sezione Downloads, i sorgenti per ora sono disponibili gratuitamente previa richiesta tramite messaggio o email.



Codifica per Bugs & Features

I titoli delle sezioni rispettano la seguente struttura:


NNNN - [X] - TTTTT


Dove NNNN è il numero univoco del bug o feature segnalato, X può essere B(bug) oppure F(nuova feature), TTTT è l'argomento della modifica.


0006 - [F] - Salvare commenti su DB

Il metodo statico saveSqlDocGenerator della classe org.dgl.sqldocgen.Util è stato rinominato in saveSqlDocGeneratorToFile, è stato quindi creato un metodo simile saveSqlDocGeneratorToDB per gestire il salvataggio su Database dei commenti.

public static void saveSqlDocGeneratorToDB(SqlDocGenerator what) throws Exception {
    String sql;
    for (Table t : what.getTables()) {
        for (TableColumn tc : t.getColumns()) {
            try {
                sql = SQL.SP_DROPCOMMENT_COLUMN;
                sql = sql.replaceFirst("\\?", t.getName());
                sql = sql.replaceFirst("\\?", tc.getName());
                what.getDatabaseManager().call(sql);
            } catch (Exception ignored) {
            }
            sql = SQL.SP_ADDCOMMENT_COLUMN;
            sql = sql.replaceFirst("\\?", tc.getComment().replaceAll("'", "''"));
            sql = sql.replaceFirst("\\?", t.getName());
            sql = sql.replaceFirst("\\?", tc.getName());
            what.getDatabaseManager().call(sql);
        }
        for (TableTrigger tr : t.getTriggers()) {
            try {
                sql = SQL.SP_DROPCOMMENT_TRIGGER;
                sql = sql.replaceFirst("\\?", t.getName());
                sql = sql.replaceFirst("\\?", tr.getName());
                what.getDatabaseManager().call(sql);
            } catch (Exception ignored) {
            }
            sql = SQL.SP_ADDCOMMENT_TRIGGER;
            sql = sql.replaceFirst("\\?", tr.getComment().replaceAll("'", "''"));
            sql = sql.replaceFirst("\\?", t.getName());
            sql = sql.replaceFirst("\\?", tr.getName());
            what.getDatabaseManager().call(sql);
        }
        try {
            sql = SQL.SP_DROPCOMMENT_TABLE;
            sql = sql.replaceFirst("\\?", t.getName());
            what.getDatabaseManager().call(sql);
        } catch (Exception ignored) {
        }
        sql = SQL.SP_ADDCOMMENT_TABLE;
        sql = sql.replaceFirst("\\?", t.getComment().replaceAll("'", "''"));
        sql = sql.replaceFirst("\\?", t.getName());
        what.getDatabaseManager().call(sql);
    }
    for (View v : what.getViews()) {
        try {
            sql = SQL.SP_DROPCOMMENT_VIEW;
            sql = sql.replaceFirst("\\?", v.getName());
            what.getDatabaseManager().call(sql);
        } catch (Exception ignored) {
        }
        sql = SQL.SP_ADDCOMMENT_VIEW;
        sql = sql.replaceFirst("\\?", v.getComment().replaceAll("'", "''"));
        sql = sql.replaceFirst("\\?", v.getName());
        what.getDatabaseManager().call(sql);
    }
    for (StoredProcedure sp : what.getStoredProcedures()) {
        try {
            sql = SQL.SP_DROPCOMMENT_STOREDPROCEDURE;
            sql = sql.replaceFirst("\\?", sp.getName());
            what.getDatabaseManager().call(sql);
        } catch (Exception ignored) {
        }
        sql = SQL.SP_ADDCOMMENT_STOREDPROCEDURE;
        sql = sql.replaceFirst("\\?", sp.getComment().replaceAll("'", "''"));
        sql = sql.replaceFirst("\\?", sp.getName());
        what.getDatabaseManager().call(sql);
    }
}

Dove le nuove istruzioni sql sono state inserite nella classe org.dgl.sqldocgen.SQL:

public static final String SP_DROPCOMMENT_TABLE = "{CALL SP_DROPEXTENDEDPROPERTY('MS_Description','Schema','dbo','Table','?')}";
public static final String SP_DROPCOMMENT_COLUMN = "{CALL SP_DROPEXTENDEDPROPERTY('MS_Description','Schema','dbo','Table','?','Column','?')}";
public static final String SP_DROPCOMMENT_TRIGGER = "{CALL SP_DROPEXTENDEDPROPERTY('MS_Description','Schema','dbo','Table','?','Trigger','?')}";
public static final String SP_DROPCOMMENT_VIEW = "{CALL SP_DROPEXTENDEDPROPERTY('MS_Description','Schema','dbo','View','?')}";
public static final String SP_DROPCOMMENT_STOREDPROCEDURE = "{CALL SP_DROPEXTENDEDPROPERTY('MS_Description','Schema','dbo','Procedure','?')}";
public static final String SP_ADDCOMMENT_TABLE = "{CALL SP_ADDEXTENDEDPROPERTY('MS_Description',N'?','Schema','dbo','Table','?')}";
public static final String SP_ADDCOMMENT_COLUMN = "{CALL SP_ADDEXTENDEDPROPERTY('MS_Description',N'?','Schema','dbo','Table','?','Column','?')}";
public static final String SP_ADDCOMMENT_TRIGGER = "{CALL SP_ADDEXTENDEDPROPERTY('MS_Description',N'?','Schema','dbo','Table','?','Trigger',N'?')}";
public static final String SP_ADDCOMMENT_VIEW = "{CALL SP_ADDEXTENDEDPROPERTY('MS_Description',N'?','Schema','dbo','View','?')}";
public static final String SP_ADDCOMMENT_STOREDPROCEDURE = "{CALL SP_ADDEXTENDEDPROPERTY('MS_Description',N'?','Schema','dbo','Procedure','?')}";

Notare che è necessario effettuare un DROP della proprietà estesa prima di inserirne il nuovo valore (potrebbe essere utilizzata la stored procedure di update di una proprietà estesa ma non sempre è sicuro che ci sia!). Dato che è possibile che la proprietà non sia presente, il drop della proprietà viene inserito in un blocco trycatch ignorato.

Per quanto riguarda l'interfaccia grafica della applicazione, il menu si popola di una nuova voce "salva su DB" rinominando quella presente da "salva" a "salva su File". Questo a tutti gli effetti si ha con il refactoring di saveMenuItem in saveToFileMenuItem e la gestione di saveToDBMenuItem. Quando viene gestito l'action listener di saveToDBMenuItem il codice non fa altro che eseguire la funzione saveSqlDocGeneratorToDB sopra descritta.

Naturalmente anche il file di linguaggio ITA.Properties deve essere aggiornato per contenere i valori giusti:

  • SQLDOCGENERATORFRAME_SAVETOFILEMENUITEM testo del comando "salva su file"
  • SQLDOCGENERATORFRAME_SAVETODBMENUITEM testo del comando "salva su DB"
Per mantenere la compatibilità è stato fatto un controllo per cui se non viene valorizzato il campo SQLDOCGENERATORFRAME_SAVETOFILEMENUITEM viene preso quello del "vecchio campo" SQLDOCGENERATORFRAME_SAVEMENUITEM.

0007 - [F] - Caricare commenti su DB

Dal momento in cui i commenti possono essere contenuti direttamente su Database, è stato inserita una domanda all'utente per chiedere se desidera caricare i commenti dal database, se presenti. Questo viene chiesto sia nel caso di caricamento da file che in caso di nuova connessione.


ATTENZIONE: I commenti caricati da DB vengono sovrascritti da quelli caricati dal file di salvataggio SDGF

Il metodo read della classe org.dgl.sqldocgen.SqlDocGenerator è stato modificato accettando in ingresso un flag che indica il caricamento dei commenti da database. Questi sono i metodi di caricamento modificati:


private void readTables(boolean loadCommentsFromDB) throws Exception {
    String sql;
    ResultSet tableResult, columnResult, triggerResult, commentResult;
    sql = SQL.QUERY_TABLES;
    tableResult = getDatabaseManager().query(sql);
    while (tableResult.next()) {
        Table table;
        table = Table.parse(tableResult);
        if (loadCommentsFromDB) {
            sql = SQL.QUERY_GETCOMMENT_TABLE;
            sql = sql.replaceFirst("\\?", "" + table.getId());
            commentResult = getDatabaseManager().query(sql);
            if (commentResult.next()) {
                table.setComment(commentResult.getString("value"));
            }
            commentResult.close();
        }
        sql = SQL.QUERY_COLUMNS;
        sql = sql.replaceFirst("\\?", "" + table.getId());
        columnResult = getDatabaseManager().query(sql);
        while (columnResult.next()) {
            TableColumn tc = TableColumn.parse(columnResult);
            if (loadCommentsFromDB) {
                sql = SQL.QUERY_GETCOMMENT_COLUMN;
                sql = sql.replaceFirst("\\?", "" + table.getId());
                sql = sql.replaceFirst("\\?", "" + tc.getId());
                commentResult = getDatabaseManager().query(sql);
                if (commentResult.next()) {
                    tc.setComment(commentResult.getString("value"));
                }
                commentResult.close();
            }
            table.getColumns().add(tc);
        }
        columnResult.close();
        sql = SQL.QUERY_TRIGGERS;
        sql = sql.replaceFirst("\\?", "" + table.getId());
        triggerResult = getDatabaseManager().query(sql);
        while (triggerResult.next()) {
            TableTrigger trigger;
            trigger = TableTrigger.parse(triggerResult);
            if (loadCommentsFromDB) {
                sql = SQL.QUERY_GETCOMMENT_TRIGGER;
                sql = sql.replaceFirst("\\?", "" + trigger.getId());
                commentResult = getDatabaseManager().query(sql);
                if (commentResult.next()) {
                    trigger.setComment(commentResult.getString("value"));
                }
                commentResult.close();
            }
            if (table.getTriggers().contains(trigger)) {
                TableTrigger original = table.getTriggers().get(table.getTriggers().indexOf(trigger));
                original.setCode(original.getCode() + trigger.getCode());
            } else {
                table.getTriggers().add(trigger);
            }
        }
        triggerResult.close();
        getTables().add(table);
    }
    tableResult.close();
}

private void readStoredProcedures(boolean loadCommentsFromDB) throws Exception {
    String sql;
    ResultSet storedProceduresResult, commentResult;
    sql = SQL.QUERY_STOREDPROCEDURES;
    storedProceduresResult = getDatabaseManager().query(sql);
    while (storedProceduresResult.next()) {
        StoredProcedure storedProcedure;
        storedProcedure = StoredProcedure.parse(storedProceduresResult);
        if (loadCommentsFromDB) {
            sql = SQL.QUERY_GETCOMMENT_STOREDPROCEDURE;
            sql = sql.replaceFirst("\\?", "" + storedProcedure.getId());
            commentResult = getDatabaseManager().query(sql);
            if (commentResult.next()) {
                storedProcedure.setComment(commentResult.getString("value"));
            }
            commentResult.close();
        }
        getStoredProcedures().add(storedProcedure);
    }
    storedProceduresResult.close();
}

private void readViews(boolean loadCommentsFromDB) throws Exception {
    String sql;
    ResultSet viewsResult, commentResult;
    sql = SQL.QUERY_VIEWS;
    viewsResult = getDatabaseManager().query(sql);
    while (viewsResult.next()) {
        View view;
        view = View.parse(viewsResult);
        if (loadCommentsFromDB) {
            sql = SQL.QUERY_GETCOMMENT_VIEW;
            sql = sql.replaceFirst("\\?", "" + view.getId());
            commentResult = getDatabaseManager().query(sql);
            if (commentResult.next()) {
                view.setComment(commentResult.getString("value"));
            }
            commentResult.close();
        }
        getViews().add(view);
    }
    viewsResult.close();
}

Queste sono le query utilizzate per ricavare il commento.
public static final String QUERY_GETCOMMENT_TABLE = "select * from sys.extended_properties where major_id = ? and minor_id = 0 and name = 'MS_Description'";
public static final String QUERY_GETCOMMENT_COLUMN = "select * from sys.extended_properties where major_id = ? and minor_id = ? and name = 'MS_Description'";
public static final String QUERY_GETCOMMENT_TRIGGER = "select * from sys.extended_properties where major_id = ? and minor_id = 0 and name = 'MS_Description'";
public static final String QUERY_GETCOMMENT_VIEW = "select * from sys.extended_properties where major_id = ? and minor_id = 0 and name = 'MS_Description'";
public static final String QUERY_GETCOMMENT_STOREDPROCEDURE = "select * from sys.extended_properties where major_id = ? and minor_id = 0 and name = 'MS_Description'";

Nessun commento:

Posta un commento