this merges the master head of https://github.com/helma-org/apps-modules-mirror into helma
341 lines
12 KiB
JavaScript
341 lines
12 KiB
JavaScript
/*
|
|
* Helma License Notice
|
|
*
|
|
* The contents of this file are subject to the Helma License
|
|
* Version 2.0 (the "License"). You may not use this file except in
|
|
* compliance with the License. A copy of the License is available at
|
|
* http://adele.helma.org/download/helma/license.txt
|
|
*
|
|
* Copyright 1998-2006 Helma Software. All Rights Reserved.
|
|
*
|
|
* $RCSfile: Database.js,v $
|
|
* $Author$
|
|
* $Revision$
|
|
* $Date$
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview Properties and methods of the helma.Database prototype.
|
|
* <br /><br />
|
|
* To use this optional module, its repository needs to be added to the
|
|
* application, for example by calling app.addRepository('modules/helma/Database.js')
|
|
*/
|
|
|
|
if (!global.helma) {
|
|
global.helma = {};
|
|
}
|
|
|
|
/**
|
|
* Constructor for Database objects, providing access through relational
|
|
* databases through JDBC. It is usually simpler to use one of the factory
|
|
* methods {@link #createInstance} or {@link #getInstance}.
|
|
* @class <p>This class provides access to a relational database through JDBC.
|
|
* There are two convenient ways to create instances of this class.</p>
|
|
*
|
|
* <p>The first is to use {@link #getInstance helma.Database.getInstance()}
|
|
* to obtain a connection to a DB that is defined in the application's
|
|
* db.properties and managed by Helma. The second way is to define and create
|
|
* a database connection locally using
|
|
* {@link #createInstance helma.Database.createInstance()} and passing it
|
|
* all necessary parameters.</p>
|
|
*
|
|
* <p>This class provides two ways of interaction:
|
|
* The {@link #query} method allows to issue SQL queries, returning a result set.
|
|
* The {@link #execute} provides a way to issue SQL statements that do not
|
|
* return a result set.</p>
|
|
*
|
|
* <p>Database connections allocated by this class are be managed and eventually
|
|
* disposed by Helma.</p>
|
|
*
|
|
* @param {DbSource} source instance of a helma.objectmodel.db.DbSource
|
|
* @constructor
|
|
*/
|
|
helma.Database = function(source) {
|
|
var Types = java.sql.Types;
|
|
var DbSource = Packages.helma.objectmodel.db.DbSource;
|
|
|
|
if (typeof(source) == "string")
|
|
source = app.getDbSource(source);
|
|
if (!(source instanceof DbSource))
|
|
throw "helma.Database requires a helma.objectmodel.db.DbSource argument";
|
|
|
|
/**
|
|
* Get the java.sql.Connection for this Database instance. This can be used
|
|
* to operate on the connection directly, without going through the helma.Database
|
|
* class.
|
|
* @return {java.sql.Connection} the JDBC connection
|
|
*/
|
|
this.getConnection = function() {
|
|
return source.getConnection();
|
|
};
|
|
|
|
/**
|
|
* Returns the lower case name of the underlying database product.
|
|
* @return {String} the name of the DB product
|
|
*/
|
|
this.getProductName = function() {
|
|
return source.getConnection().getMetaData().getDatabaseProductName().toLowerCase();
|
|
};
|
|
|
|
/**
|
|
* Returns true if this is an Oracle database.
|
|
* @return {boolean} true if this is an Oracle database.
|
|
*/
|
|
this.isOracle = function() {
|
|
return source.isOracle();
|
|
};
|
|
|
|
/**
|
|
* Returns true if this is a MySQL database.
|
|
* @return {boolean} true if this is an MySQL database.
|
|
*/
|
|
this.isMySql = function() {
|
|
return source.isMySQL();
|
|
};
|
|
|
|
/**
|
|
* Returns true if this is a PostgreSQL database.
|
|
* @return {boolean} true if this is a PostgreSQL database.
|
|
*/
|
|
this.isPostgreSql = function() {
|
|
return source.isPostgreSQL();
|
|
};
|
|
|
|
/**
|
|
* Executes the given SQL statement. The result set is returned
|
|
* as JavaScript Array containing a JavaScript Object for each result.
|
|
* @param {String} sql an SQL query statement
|
|
* @return {Array} an Array containing the result set
|
|
*/
|
|
this.query = function(sql) {
|
|
var isLogSqlEnabled = (getProperty("logSQL", "false").toLowerCase() == "true");
|
|
var logTimeStart = isLogSqlEnabled ? java.lang.System.currentTimeMillis() : 0;
|
|
var connection = source.getConnection();
|
|
connection.setReadOnly(true);
|
|
var statement = connection.createStatement();
|
|
var resultSet = statement.executeQuery(sql);
|
|
var metaData = resultSet.getMetaData();
|
|
var max = metaData.getColumnCount();
|
|
var types = [];
|
|
for (var i=1; i <= max; i++) {
|
|
types[i] = metaData.getColumnType(i);
|
|
}
|
|
var result = [];
|
|
while (resultSet.next()) {
|
|
var row = {}
|
|
for (var i=1; i<=max; i+=1) {
|
|
switch (types[i]) {
|
|
case Types.BIT:
|
|
case Types.BOOLEAN:
|
|
row[metaData.getColumnLabel(i)] = resultSet.getBoolean(i);
|
|
break;
|
|
case Types.TINYINT:
|
|
case Types.BIGINT:
|
|
case Types.SMALLINT:
|
|
case Types.INTEGER:
|
|
row[metaData.getColumnLabel(i)] = resultSet.getLong(i);
|
|
break;
|
|
case Types.REAL:
|
|
case Types.FLOAT:
|
|
case Types.DOUBLE:
|
|
case Types.DECIMAL:
|
|
case Types.NUMERIC:
|
|
row[metaData.getColumnLabel(i)] = resultSet.getDouble(i);
|
|
break;
|
|
case Types.VARBINARY:
|
|
case Types.BINARY:
|
|
case Types.LONGVARBINARY:
|
|
case Types.LONGVARCHAR:
|
|
case Types.CHAR:
|
|
case Types.VARCHAR:
|
|
case Types.CLOB:
|
|
case Types.OTHER:
|
|
row[metaData.getColumnLabel(i)] = resultSet.getString(i);
|
|
break;
|
|
case Types.DATE:
|
|
case Types.TIME:
|
|
case Types.TIMESTAMP:
|
|
row[metaData.getColumnLabel(i)] = resultSet.getTimestamp(i);
|
|
break;
|
|
case Types.NULL:
|
|
row[metaData.getColumnLabel(i)] = null;
|
|
break;
|
|
default:
|
|
row[metaData.getColumnLabel(i)] = resultSet.getString(i);
|
|
break;
|
|
}
|
|
}
|
|
result[result.length] = row;
|
|
}
|
|
var logTimeStop = isLogSqlEnabled ? java.lang.System.currentTimeMillis() : 0;
|
|
if (isLogSqlEnabled) {
|
|
var tableName = metaData.getColumnCount() > 0 ? metaData.getTableName(1) : null;
|
|
app.getLogger("helma." + app.name + ".sql").info("SQL DIRECT_QUERY " + (tableName || "-") + " " + (logTimeStop - logTimeStart) + ": " + sql);
|
|
}
|
|
try {
|
|
statement.close();
|
|
resultSet.close();
|
|
} catch (error) {
|
|
// ignore
|
|
}
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Executes the given SQL statement, which may be an INSERT, UPDATE,
|
|
* or DELETE statement or an SQL statement that returns nothing,
|
|
* such as an SQL data definition statement. The return value is an integer that
|
|
* indicates the number of rows that were affected by the statement.
|
|
* @param {String} sql an SQL statement
|
|
* @return {int} either the row count for INSERT, UPDATE or
|
|
* DELETE statements, or 0 for SQL statements that return nothing
|
|
*/
|
|
this.execute = function(sql) {
|
|
var isLogSqlEnabled = (getProperty("logSQL", "false").toLowerCase() == "true");
|
|
var logTimeStart = isLogSqlEnabled ? java.lang.System.currentTimeMillis() : 0;
|
|
var connection = source.getConnection();
|
|
connection.setReadOnly(false);
|
|
var statement = connection.createStatement();
|
|
var result;
|
|
try {
|
|
result = statement.executeUpdate(sql);
|
|
} finally {
|
|
try {
|
|
statement.close();
|
|
} catch (error) {
|
|
// ignore
|
|
}
|
|
}
|
|
var logTimeStop = isLogSqlEnabled ? java.lang.System.currentTimeMillis() : 0;
|
|
if (isLogSqlEnabled) {
|
|
app.getLogger("helma." + app.name + ".sql").info("SQL DIRECT_EXECUTE - " + (logTimeStop - logTimeStart) + ": " + sql);
|
|
}
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Return the name of the Helma DbSource object.
|
|
* @return {String} the DbSource name
|
|
*/
|
|
this.getName = function() {
|
|
return source.getName();
|
|
};
|
|
|
|
/**
|
|
* Return the name of the JDBC driver used by this Database instance.
|
|
* @return {String} the JDBC driver name
|
|
*/
|
|
this.getDriverName = function() {
|
|
return source.getDriverName();
|
|
};
|
|
|
|
/**
|
|
* @ignore
|
|
*/
|
|
this.toString = function() {
|
|
return "[helma.Database " + this.getName() + "]";
|
|
};
|
|
|
|
for (var i in this)
|
|
this.dontEnum(i);
|
|
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Create a new Database instance using the given parameters.
|
|
* <p>Some of the parameters support shortcuts for known database products.
|
|
* The <code>url</code> parameter recognizes the values "mysql", "oracle" and
|
|
* "postgresql". For those databases, it is also possible to pass just
|
|
* <code>hostname</code> or <code>hostname:port</code> as <code>url</code>
|
|
* parameters instead of the full JDBC URL.</p>
|
|
* @param {String} driver the class name of the JDBC driver. As
|
|
* shortcuts, the values "mysql", "oracle" and "postgresql" are
|
|
* recognized.
|
|
* @param {String} url the JDBC URL.
|
|
* @param {String} name the name of the database to use
|
|
* @param {String} user the the username
|
|
* @param {String} password the password
|
|
* @return {helma.Database} a helma.Database instance
|
|
*/
|
|
helma.Database.createInstance = function(driver, url, name, user, password) {
|
|
var DbSource = Packages.helma.objectmodel.db.DbSource;
|
|
|
|
if (!driver || !url || !name)
|
|
throw("Insufficient arguments to create helma.db.Connection");
|
|
if (typeof password != "string")
|
|
password = "";
|
|
|
|
var MYSQL = "mysql";
|
|
var ORACLE = "oracle";
|
|
var POSTGRESQL = "postgresql";
|
|
var JDBC = "jdbc:";
|
|
var DRIVER_MYSQL = "com.mysql.jdbc.Driver";
|
|
var DRIVER_ORACLE = "oracle.jdbc.driver.OracleDriver";
|
|
var DRIVER_POSTGRESQL = "org.postgresql.Driver";
|
|
|
|
if (driver == MYSQL) {
|
|
driver = DRIVER_MYSQL;
|
|
if (url.indexOf(JDBC) != 0)
|
|
url = "jdbc:mysql://" + url + "/" + name;
|
|
} else if (driver == ORACLE) {
|
|
driver = DRIVER_ORACLE;
|
|
if (url.indexOf(JDBC) != 0)
|
|
url = "jdbc:oracle:thin:@" + url + ":" + name;
|
|
} else if (driver == POSTGRESQL) {
|
|
driver = DRIVER_POSTGRESQL;
|
|
if (url.indexOf(JDBC) != 0)
|
|
url = "jdbc:postgresql://" + url + "/" + name;
|
|
}
|
|
var props = new Packages.helma.util.ResourceProperties();
|
|
props.put(name + ".url", url);
|
|
props.put(name + ".driver", driver);
|
|
if (user) {
|
|
props.put(name + ".user", user)
|
|
}
|
|
if (password) {
|
|
props.put(name + ".password", password);
|
|
}
|
|
return new helma.Database(new DbSource(name, props));
|
|
}
|
|
|
|
/**
|
|
* Get a Database instance using the Database source defined in the
|
|
* application's db.properties file with the given name.
|
|
* @param {String} name the name of the DB source as defined in db.properties
|
|
* @return {helma.Database} a helma.Database instance
|
|
*/
|
|
helma.Database.getInstance = function(name) {
|
|
return new helma.Database(app.getDbSource(name));
|
|
}
|
|
|
|
/**
|
|
* @ignore
|
|
*/
|
|
helma.Database.toString = function() {
|
|
return "[helma.Database]";
|
|
};
|
|
|
|
/**
|
|
* @ignore
|
|
*/
|
|
helma.Database.example = function() {
|
|
var type = "mysql";
|
|
var host = "localhost";
|
|
var user = "root";
|
|
var pw = "";
|
|
var name = "mysql";
|
|
var db = new helma.Database(type, host, user, pw, name);
|
|
var result = db.query("select count(*) from db");
|
|
res.write(result.toSource());
|
|
return;
|
|
};
|
|
|
|
|
|
helma.lib = "Database";
|
|
helma.dontEnum(helma.lib);
|
|
for (var i in helma[helma.lib])
|
|
helma[helma.lib].dontEnum(i);
|
|
for (var i in helma[helma.lib].prototype)
|
|
helma[helma.lib].prototype.dontEnum(i);
|
|
delete helma.lib;
|