Skip to content

Commit

Permalink
First pass at adding support for stored procedures
Browse files Browse the repository at this point in the history
  • Loading branch information
johncurrier committed Apr 5, 2011
1 parent 5f44e05 commit 4b2b0db
Show file tree
Hide file tree
Showing 11 changed files with 348 additions and 8 deletions.
9 changes: 9 additions & 0 deletions src/net/sourceforge/schemaspy/SchemaAnalyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import net.sourceforge.schemaspy.view.HtmlMainIndexPage;
import net.sourceforge.schemaspy.view.HtmlOrphansPage;
import net.sourceforge.schemaspy.view.HtmlRelationshipsPage;
import net.sourceforge.schemaspy.view.HtmlRoutinesPage;
import net.sourceforge.schemaspy.view.HtmlTablePage;
import net.sourceforge.schemaspy.view.ImageWriter;
import net.sourceforge.schemaspy.view.StyleSheet;
Expand Down Expand Up @@ -305,6 +306,7 @@ public Database analyze(Config config) throws Exception {

List<Table> orphans = DbAnalyzer.getOrphans(tables);
config.setHasOrphans(!orphans.isEmpty() && Dot.getInstance().isValid());
config.setHasRoutines(!db.getRoutines().isEmpty());

if (!fineEnabled)
System.out.print(".");
Expand Down Expand Up @@ -371,6 +373,13 @@ public Database analyze(Config config) throws Exception {
out.close();
}

if (!fineEnabled)
System.out.print(".");

out = new LineWriter(new File(outputDir, "routines.html"), 16 * 1024, config.getCharset());
HtmlRoutinesPage.getInstance().write(db, out);
out.close();

// create detailed diagrams

startDiagrammingDetails = System.currentTimeMillis();
Expand Down
8 changes: 7 additions & 1 deletion src/net/sourceforge/schemaspy/dbTypes/mysql.properties
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ selectRowCountSql=select table_rows row_count from information_schema.tables whe
# short_column_type is optional and is used in the ER diagrams to keep them from becoming bloated
selectColumnTypesSql=select table_name, column_name, replace(column_type,"','","', '") as column_type, left(column_type, locate("(", column_type)-1) as short_column_type from information_schema.columns where table_schema=:schema and (column_type like 'enum(%' or column_type like 'set(%')

# select any stored procedures and functions
selectRoutinesSql=select routine_name, routine_type, dtd_identifier, routine_body, routine_definition, is_deterministic, sql_data_access, security_type, sql_mode, routine_comment from information_schema.routines where routine_schema=:schema

# select parameters for stored procedures and functions
selectRoutineParametersSql=select specific_name, parameter_name, dtd_identifier, parameter_mode from information_schema.parameters where specific_schema=:schema and ordinal_position != 0 order by ordinal_position

# regular expression used in conjunction with -all (and can be command line param '-schemaSpec')
# this says which schemas to include in our evaluation of "all schemas"
# this one matches anything other than the listed system tables
schemaSpec=(?!^mysql$|^performance_schema$|^information_schema$).*
schemaSpec=(?!^mysql$|^performance_schema$|^information_schema$).*
88 changes: 88 additions & 0 deletions src/net/sourceforge/schemaspy/model/Database.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public class Database {
private final Map<String, View> views = new CaseInsensitiveMap<View>();
private final Map<String, Table> remoteTables = new CaseInsensitiveMap<Table>(); // key: schema.tableName
private final Map<String, Table> locals = new CombinedMap(tables, views);
private final Map<String, Routine> routines = new CaseInsensitiveMap<Routine>();
private final DatabaseMetaData meta;
private final Connection connection;
private final String connectTime = new SimpleDateFormat("EEE MMM dd HH:mm z yyyy").format(new Date());
Expand Down Expand Up @@ -83,6 +84,7 @@ public Database(Config config, Connection connection, DatabaseMetaData meta, Str
initViewComments(properties);
initViewColumnComments(properties);
initColumnTypes(properties);
initRoutines(properties);

connectTables();
updateFromXmlMetadata(schemaMeta, properties);
Expand Down Expand Up @@ -130,6 +132,10 @@ public Collection<Table> getRemoteTables() {
return remoteTables.values();
}

public Collection<Routine> getRoutines() {
return routines.values();
}

public Connection getConnection() {
return connection;
}
Expand Down Expand Up @@ -731,6 +737,88 @@ private void initViewColumnComments(Properties properties) throws SQLException {
}
}

/**
* Initializes stored procedures / functions.
*
* @param properties
* @throws SQLException
*/
private void initRoutines(Properties properties) throws SQLException {
String sql = properties.getProperty("selectRoutinesSql");

if (sql != null) {
PreparedStatement stmt = null;
ResultSet rs = null;

try {
stmt = prepareStatement(sql, null);
rs = stmt.executeQuery();

while (rs.next()) {
String routineName = rs.getString("routine_name");
String routineType = rs.getString("routine_type");
String returnType = rs.getString("dtd_identifier");
String definitionLanguage = rs.getString("routine_body");
String definition = rs.getString("routine_definition");
String dataAccess = rs.getString("sql_data_access");
String securityType = rs.getString("security_type");
boolean deterministic = rs.getBoolean("is_deterministic");
String comment = getOptionalString(rs, "routine_comment");

Routine routine = new Routine(routineName, routineType,
returnType, definitionLanguage, definition,
deterministic, dataAccess, securityType, comment);
routines.put(routineName, routine);
}
} catch (SQLException sqlException) {
// don't die just because this failed
warning("Failed to retrieve stored procedure/function details: " + sqlException, sql);
} finally {
if (rs != null)
rs.close();
if (stmt != null)
stmt.close();
rs = null;
stmt = null;
}
}

sql = properties.getProperty("selectRoutineParametersSql");

if (sql != null) {
PreparedStatement stmt = null;
ResultSet rs = null;

try {
stmt = prepareStatement(sql, null);
rs = stmt.executeQuery();

while (rs.next()) {
String routineName = rs.getString("specific_name");

Routine routine = routines.get(routineName);
if (routine != null) {
String paramName = rs.getString("parameter_name");
String type = rs.getString("dtd_identifier");
String mode = rs.getString("parameter_mode");

RoutineParameter param = new RoutineParameter(paramName, type, mode);
routine.addParameter(param);
}

}
} catch (SQLException sqlException) {
// don't die just because this failed
warning("Failed to retrieve stored procedure/function details: " + sqlException, sql);
} finally {
if (rs != null)
rs.close();
if (stmt != null)
stmt.close();
}
}
}

/**
* Dump a warning message out to a new line
*
Expand Down
163 changes: 163 additions & 0 deletions src/net/sourceforge/schemaspy/model/Routine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* This file is a part of the SchemaSpy project (http://schemaspy.sourceforge.net).
* Copyright (C) 2011 John Currier
*
* SchemaSpy is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* SchemaSpy 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.sourceforge.schemaspy.model;

import java.util.ArrayList;
import java.util.List;

/**
* Metadata about a stored procedure or function
*
* @author John Currier
*/
public class Routine implements Comparable<Routine> {
private final String name;
private final String type;
private final String definitionLanguage;
private final String definition;
private final boolean deterministic;
private final String dataAccess;
private final String securityType;
private final String comment;
private final String returnType;
private final List<RoutineParameter> params = new ArrayList<RoutineParameter>();

/**
* @param name
* @param type
* @param returnType
* @param definitionLanguage
* @param definition
* @param deterministic
* @param dataAccess
* @param securityType
* @param comment
*/
public Routine(String name,
String type, // function or procedure
String returnType,
String definitionLanguage,
String definition,
boolean deterministic, String dataAccess,
String securityType, String comment) {
this.name = name;
this.type = type;
this.returnType = returnType;
this.definitionLanguage = definitionLanguage;
this.definition = definition;
this.dataAccess = dataAccess;
this.securityType = securityType;
this.deterministic = deterministic;
this.comment = comment;
}

/**
* @return
*/
public String getName() {
return name;
}

/**
* @return
*/
public String getType() {
return type;
}

/**
* @return
*/
public String getDefinitionLanguage() {
return definitionLanguage;
}

/**
* @return
*/
public String getDefinition() {
return definition;
}

/**
* @return
*/
public boolean isDeterministic() {
return deterministic;
}

/**
* @return
*/
public String getDataAccess() {
return dataAccess;
}

/**
* @return
*/
public String getSecurityType() {
return securityType;
}

/**
* @return
*/
public String getComment() {
return comment;
}

/**
* Returns the return type for the routine or null if there is none
*
* @return
*/
public String getReturnType() {
return returnType;
}

/**
* @param param
*/
public void addParameter(RoutineParameter param) {
params.add(param);
}

/**
* Returns the types of the routine's parameters.
* @return
*/
public List<RoutineParameter> getParameters() {
return params;
}

/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(Routine other) {
int rc = getName().compareTo(other.getName());
if (rc == 0)
rc = getType().compareTo(other.getType());
if (rc == 0)
rc = String.valueOf(getReturnType()).compareTo(String.valueOf(other.getReturnType()));
if (rc == 0)
rc = getDefinition().compareTo(other.getDefinition());
return rc;
}
}
62 changes: 62 additions & 0 deletions src/net/sourceforge/schemaspy/model/RoutineParameter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* This file is a part of the SchemaSpy project (http://schemaspy.sourceforge.net).
* Copyright (C) 2011 John Currier
*
* SchemaSpy is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* SchemaSpy 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.sourceforge.schemaspy.model;

/**
* Immutable metadata about a parameter used in a stored procedure or function
*
* @author John Currier
*/
public class RoutineParameter {
private final String name;
private final String type;
private final String mode;

/**
* @param name
* @param type
* @param mode
*/
public RoutineParameter(String name, String type, String mode) {
this.name = name;
this.type = type;
this.mode = mode;
}

/**
* @return
*/
public String getName() {
return name;
}

/**
* @return
*/
public String getType() {
return type;
}

/**
* @return
*/
public String getMode() {
return mode;
}
}
Loading

0 comments on commit 4b2b0db

Please sign in to comment.