1014 lines
38 KiB
Java
1014 lines
38 KiB
Java
|
// Database.java
|
||
|
// FESI Copyright (c) Jean-Marc Lugrin, 1999
|
||
|
//
|
||
|
// This program 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 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
|
||
|
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
|
||
|
package FESI.Extensions;
|
||
|
|
||
|
import FESI.Parser.*;
|
||
|
import FESI.AST.*;
|
||
|
import FESI.Interpreter.*;
|
||
|
import FESI.Exceptions.*;
|
||
|
import FESI.Data.*;
|
||
|
|
||
|
import java.util.Date;
|
||
|
import java.util.Enumeration;
|
||
|
import java.util.Vector;
|
||
|
import java.sql.*;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* A Database object, representing a connection to a JDBC Driver
|
||
|
*/
|
||
|
class ESDatabase extends ESObject {
|
||
|
|
||
|
private transient Connection connection = null; // Null if not connected
|
||
|
private transient DatabaseMetaData databaseMetaData = null;
|
||
|
private transient String driverName = null;
|
||
|
private transient ClassLoader driverLoader = null;
|
||
|
private transient Exception lastError = null;
|
||
|
private transient ESObject esRowSetPrototype = null;
|
||
|
private transient boolean driverOK = false;
|
||
|
|
||
|
/**
|
||
|
* Create a new database object based on a driver name, with driver on the classpath
|
||
|
*
|
||
|
* @param prototype The prototype object for all database object
|
||
|
* @param evaluator The current evaluator
|
||
|
* @param esRowSetPrototype The prototype to use to create row set
|
||
|
* @param driverName The class name of the JDBC driver
|
||
|
*/
|
||
|
|
||
|
ESDatabase(ESObject prototype,
|
||
|
Evaluator evaluator,
|
||
|
ESObject esRowSetPrototype,
|
||
|
String driverName) {
|
||
|
super(prototype, evaluator);
|
||
|
this.driverName = driverName;
|
||
|
this.esRowSetPrototype = esRowSetPrototype; // specific to an evaluator
|
||
|
try {
|
||
|
Class driverClass = Class.forName(driverName);
|
||
|
if (!Driver.class.isAssignableFrom(driverClass)) {
|
||
|
// System.err.println("##Bad class " + driverClass);
|
||
|
lastError = new EcmaScriptException("Class " + driverClass + " is not a JDBC driver");
|
||
|
}
|
||
|
driverClass.newInstance(); // may be needed by some drivers, harmless for others
|
||
|
} catch (ClassNotFoundException e) {
|
||
|
// System.err.println("##Cannot find driver class: " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
} catch (InstantiationException e) {
|
||
|
// System.err.println("##Cannot instantiate driver class: " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
} catch (IllegalAccessException e) {
|
||
|
// ignore as this may happen depending on driver, it may not be severe
|
||
|
// for example because the instance was created at class initialization time
|
||
|
}
|
||
|
driverOK = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a new database object based on a driver name and its classpath
|
||
|
*
|
||
|
* @param prototype The prototype object for all database object
|
||
|
* @param evaluator The current evaluator
|
||
|
* @param esRowSetPrototype The prototype to use to create row set
|
||
|
* @param driverName The class name of the JDBC driver
|
||
|
* @param pathName The path to the classes of the JDBC driver
|
||
|
*/
|
||
|
ESDatabase(ESObject prototype,
|
||
|
Evaluator evaluator,
|
||
|
ESObject esRowSetPrototype,
|
||
|
String driverName,
|
||
|
String pathName) {
|
||
|
super(prototype, evaluator);
|
||
|
this.driverName = driverName;
|
||
|
this.esRowSetPrototype = esRowSetPrototype;
|
||
|
try {
|
||
|
this.driverLoader = LocalClassLoader.makeLocalClassLoader(pathName);
|
||
|
} catch (EcmaScriptException e) {
|
||
|
// System.err.println("##Cannot find driver class: " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
return;
|
||
|
}
|
||
|
try {
|
||
|
Class driverClass = driverLoader.loadClass(driverName);
|
||
|
if (!Driver.class.isAssignableFrom(driverClass)) {
|
||
|
// System.err.println("##Bad class " + driverClass);
|
||
|
// e.printStackTrace();
|
||
|
lastError = new EcmaScriptException("Class " + driverClass + " is not a JDBC driver");
|
||
|
return;
|
||
|
}
|
||
|
driverClass.newInstance();
|
||
|
} catch (ClassNotFoundException e) {
|
||
|
// System.err.println("##Cannot find driver class: " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
} catch (InstantiationException e) {
|
||
|
// System.err.println("##Cannot instantiate driver class: " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
} catch (IllegalAccessException e) {
|
||
|
// System.err.println("##Cannot access driver class: " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
}
|
||
|
driverOK = true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create the database prototype object which cannot be connected
|
||
|
*
|
||
|
* @param prototype The prototype object for the database prototype object
|
||
|
* @param evaluator The current evaluator
|
||
|
*/
|
||
|
|
||
|
ESDatabase(ESObject prototype,
|
||
|
Evaluator evaluator) {
|
||
|
super(prototype, evaluator);
|
||
|
this.driverName = null;
|
||
|
this.esRowSetPrototype = null;
|
||
|
driverOK = false; // Avoid usage of this object
|
||
|
}
|
||
|
|
||
|
public String getESClassName() {
|
||
|
return "Database";
|
||
|
}
|
||
|
|
||
|
public String toString() {
|
||
|
if (driverName==null) return "[database protoype]";
|
||
|
return "[Database: '" + driverName +
|
||
|
(driverOK ?
|
||
|
(connection==null ? "' - disconnected] " : " - connected]")
|
||
|
: " - in error]");
|
||
|
}
|
||
|
|
||
|
public String toDetailString() {
|
||
|
return "ES:[Object: builtin " + this.getClass().getName() + ":" +
|
||
|
this.toString() + "]";
|
||
|
}
|
||
|
|
||
|
ESValue getLastError() throws EcmaScriptException {
|
||
|
if (lastError == null) {
|
||
|
return ESNull.theNull;
|
||
|
} else {
|
||
|
return ESLoader.normalizeValue(lastError, evaluator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Connect to the database, using the specific url, optional user name and password
|
||
|
*
|
||
|
* @param arguments The argument list
|
||
|
* @return true if successful, false otherwise
|
||
|
*/
|
||
|
ESValue connect(ESValue arguments[]) throws EcmaScriptException {
|
||
|
if (!driverOK) {
|
||
|
throw new EcmaScriptException("Driver not initialized properly - cannot connect");
|
||
|
}
|
||
|
lastError = null;
|
||
|
String url = (arguments.length>0) ? arguments[0].toString() : null;
|
||
|
String userName = (arguments.length>1) ? arguments[1].toString() : null;
|
||
|
String password = (arguments.length>2) ? arguments[2].toString() : null;
|
||
|
try {
|
||
|
if (userName == null) {
|
||
|
connection = DriverManager.getConnection(url);
|
||
|
} else {
|
||
|
connection = DriverManager.getConnection(url,userName,password);
|
||
|
}
|
||
|
} catch(Exception e) {
|
||
|
// System.err.println("##Cannot connect: " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
return ESBoolean.makeBoolean(false);
|
||
|
}
|
||
|
return ESBoolean.makeBoolean(true);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Disconnect from the database, nop if not conected
|
||
|
*
|
||
|
* @return true if successful, false if error during idsconnect
|
||
|
*/
|
||
|
ESValue disconnect() throws EcmaScriptException {
|
||
|
if (!driverOK) {
|
||
|
throw new EcmaScriptException("Driver not initialized properly - cannot disconnect");
|
||
|
}
|
||
|
lastError = null;
|
||
|
if (connection != null) {
|
||
|
try {
|
||
|
connection.close();
|
||
|
connection = null;
|
||
|
lastError = null;
|
||
|
} catch (SQLException e) {
|
||
|
// System.err.println("##Cannot disonnect: " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
return ESBoolean.makeBoolean(false);
|
||
|
}
|
||
|
}
|
||
|
return ESBoolean.makeBoolean(true);
|
||
|
}
|
||
|
|
||
|
ESValue release() {
|
||
|
if (driverOK) {
|
||
|
try {
|
||
|
disconnect();
|
||
|
} catch (EcmaScriptException e) {
|
||
|
// ignored
|
||
|
}
|
||
|
}
|
||
|
return ESUndefined.theUndefined;
|
||
|
}
|
||
|
|
||
|
ESValue executeRetrieval(ESValue arguments[]) throws EcmaScriptException {
|
||
|
String sql = (arguments.length>0) ? arguments[0].toString() : null;
|
||
|
|
||
|
if (connection==null) {
|
||
|
throw new EcmaScriptException("JDBC driver not connected");
|
||
|
}
|
||
|
Statement statement = null;
|
||
|
ResultSet resultSet = null;
|
||
|
|
||
|
try {
|
||
|
statement = connection.createStatement();
|
||
|
resultSet = statement.executeQuery(sql); // will return true if first result is a result set
|
||
|
} catch(SQLException e) {
|
||
|
// System.err.println("##Cannot retrieve: " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
try {
|
||
|
if (statement!=null) statement.close();
|
||
|
} catch (Exception ignored) {
|
||
|
}
|
||
|
statement = null;
|
||
|
return ESBoolean.makeBoolean(false);
|
||
|
}
|
||
|
ESRowSet rowSet = new ESRowSet(esRowSetPrototype, evaluator, sql, this, statement, resultSet);
|
||
|
return rowSet;
|
||
|
//return ESBoolean.makeBoolean(true);
|
||
|
}
|
||
|
|
||
|
ESValue executeCommand(ESValue arguments[]) throws EcmaScriptException {
|
||
|
String sql = (arguments.length>0) ? arguments[0].toString() : null;
|
||
|
int count = 0;
|
||
|
|
||
|
if (connection==null) {
|
||
|
throw new EcmaScriptException("JDBC driver not connected");
|
||
|
}
|
||
|
|
||
|
Statement statement = null;
|
||
|
try {
|
||
|
|
||
|
statement = connection.createStatement();
|
||
|
count = statement.executeUpdate(sql); // will return true if first result is a result set
|
||
|
} catch(SQLException e) {
|
||
|
// System.err.println("##Cannot retrieve: " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
try {
|
||
|
if (statement != null) statement.close();
|
||
|
} catch (Exception ignored) {
|
||
|
}
|
||
|
statement = null;
|
||
|
return ESBoolean.makeBoolean(false);
|
||
|
}
|
||
|
if (statement!=null) try {
|
||
|
statement.close();
|
||
|
} catch (SQLException e) {
|
||
|
// ignored
|
||
|
}
|
||
|
return new ESNumber(count);
|
||
|
//return ESBoolean.makeBoolean(true);
|
||
|
}
|
||
|
|
||
|
public Object getMetaData()
|
||
|
{
|
||
|
if (databaseMetaData == null)
|
||
|
try {
|
||
|
databaseMetaData = connection.getMetaData();
|
||
|
} catch (SQLException e) {
|
||
|
// ignored
|
||
|
}
|
||
|
return databaseMetaData;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* A RowSet object
|
||
|
*/
|
||
|
class ESRowSet extends ESObject {
|
||
|
|
||
|
private transient ESDatabase database = null;
|
||
|
private transient String sql = null;
|
||
|
private transient Statement statement = null;
|
||
|
private transient ResultSet resultSet = null;
|
||
|
private transient ResultSetMetaData resultSetMetaData = null;
|
||
|
private transient Vector colNames = null;
|
||
|
private transient boolean lastRowSeen = false;
|
||
|
private transient boolean firstRowSeen = false;
|
||
|
private transient Exception lastError = null;
|
||
|
|
||
|
ESRowSet(ESObject prototype,
|
||
|
Evaluator evaluator,
|
||
|
String sql,
|
||
|
ESDatabase database,
|
||
|
Statement statement,
|
||
|
ResultSet resultSet) throws EcmaScriptException {
|
||
|
super(prototype, evaluator);
|
||
|
this.sql = sql;
|
||
|
this.database = database;
|
||
|
this.statement = statement;
|
||
|
this.resultSet = resultSet;
|
||
|
|
||
|
if (sql==null) throw new NullPointerException();
|
||
|
if (resultSet==null) throw new NullPointerException();
|
||
|
if (statement==null) throw new NullPointerException();
|
||
|
if (database==null) throw new NullPointerException();
|
||
|
|
||
|
try {
|
||
|
|
||
|
this.resultSetMetaData = resultSet.getMetaData();
|
||
|
int numcols = resultSetMetaData.getColumnCount();
|
||
|
//System.out.println("$$NEXT : " + numcols);
|
||
|
colNames = new Vector(numcols);
|
||
|
for (int i=0; i<numcols; i++) {
|
||
|
String colName = resultSetMetaData.getColumnLabel(i+1);
|
||
|
//System.out.println("$$COL : " + colName);
|
||
|
colNames.addElement(colName);
|
||
|
}
|
||
|
} catch(SQLException e) {
|
||
|
colNames = new Vector(); // An empty one
|
||
|
throw new EcmaScriptException("Could not get column names", e);
|
||
|
|
||
|
// System.err.println("##Cannot get column names: " + e);
|
||
|
// e.printStackTrace();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
public String getESClassName() {
|
||
|
return "RowSet";
|
||
|
}
|
||
|
|
||
|
public String toDetailString() {
|
||
|
return "ES:[Object: builtin " + this.getClass().getName() + ":" +
|
||
|
this.toString() + "]";
|
||
|
}
|
||
|
|
||
|
public int getColumnCount() {
|
||
|
return colNames.size();
|
||
|
}
|
||
|
|
||
|
public Object getMetaData()
|
||
|
{
|
||
|
return resultSetMetaData;
|
||
|
}
|
||
|
|
||
|
ESValue getLastError() throws EcmaScriptException {
|
||
|
if (lastError == null) {
|
||
|
return ESUndefined.theUndefined;
|
||
|
} else {
|
||
|
return ESLoader.normalizeValue(lastError, evaluator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
ESValue release() {
|
||
|
try {
|
||
|
if (statement!= null) statement.close();
|
||
|
if (resultSet != null) resultSet.close();
|
||
|
} catch (SQLException e) {
|
||
|
// ignored
|
||
|
}
|
||
|
statement = null;
|
||
|
resultSet = null;
|
||
|
resultSetMetaData = null;
|
||
|
return ESUndefined.theUndefined;
|
||
|
}
|
||
|
|
||
|
public boolean hasMoreRows() {
|
||
|
return !lastRowSeen; // Simplistic implementation
|
||
|
}
|
||
|
|
||
|
public String getColumnName(int idx) throws EcmaScriptException {
|
||
|
if (resultSet == null) {
|
||
|
throw new EcmaScriptException("Attempt to access a released result set");
|
||
|
}
|
||
|
if (idx>0 && idx <=colNames.size()) {
|
||
|
return (String) colNames.elementAt(idx-1); // to base 0
|
||
|
} else {
|
||
|
throw new EcmaScriptException("Column index (base 1) " + idx +
|
||
|
" out of range, max: " +colNames.size());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
public int getColumnDatatypeNumber(int idx) throws EcmaScriptException {
|
||
|
if (resultSet == null) {
|
||
|
throw new EcmaScriptException("Attempt to access a released result set");
|
||
|
}
|
||
|
if (idx>0 && idx <=colNames.size()) {
|
||
|
try {
|
||
|
return resultSetMetaData.getColumnType(idx);
|
||
|
} catch (SQLException e) {
|
||
|
lastError = e;
|
||
|
return -1;
|
||
|
}
|
||
|
} else {
|
||
|
throw new EcmaScriptException("Column index (base 1) " + idx +
|
||
|
" out of range, max: " +colNames.size());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
public String getColumnDatatypeName(int idx) throws EcmaScriptException {
|
||
|
if (resultSet == null) {
|
||
|
throw new EcmaScriptException("Attempt to access a released result set");
|
||
|
}
|
||
|
if (idx>0 && idx <=colNames.size()) {
|
||
|
try {
|
||
|
return resultSetMetaData.getColumnTypeName(idx);
|
||
|
} catch (SQLException e) {
|
||
|
lastError = e;
|
||
|
return null;
|
||
|
}
|
||
|
} else {
|
||
|
throw new EcmaScriptException("Column index (base 1) " + idx +
|
||
|
" out of range, max: " +colNames.size());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
public ESValue getColumnItem(String propertyName) throws EcmaScriptException {
|
||
|
if (resultSet == null) {
|
||
|
throw new EcmaScriptException("Attempt to access a released result set");
|
||
|
}
|
||
|
if (!firstRowSeen) {
|
||
|
throw new EcmaScriptException("Attempt to access data before the first row is read");
|
||
|
}
|
||
|
int hash = propertyName.hashCode();
|
||
|
try {
|
||
|
int index = -1; // indicates not a valid index value
|
||
|
try {
|
||
|
char c = propertyName.charAt(0);
|
||
|
if ('0' <= c && c <= '9') {
|
||
|
index = Integer.parseInt(propertyName);
|
||
|
}
|
||
|
} catch (NumberFormatException e) {
|
||
|
} catch (StringIndexOutOfBoundsException e) { // for charAt
|
||
|
}
|
||
|
if (index>=0) {
|
||
|
return getProperty(index);
|
||
|
}
|
||
|
Object o = resultSet.getObject(propertyName);
|
||
|
ESValue value = ESLoader.normalizeValue(o, evaluator);
|
||
|
// System.out.println("&& @VALUE : " + value);
|
||
|
lastError = null;
|
||
|
return value;
|
||
|
} catch (SQLException e) {
|
||
|
//System.err.println("##Cannot get property '" + propertyName + "' " + e);
|
||
|
//e.printStackTrace();
|
||
|
lastError = e;
|
||
|
}
|
||
|
return ESUndefined.theUndefined;
|
||
|
}
|
||
|
|
||
|
public ESValue getProperty(String propertyName, int hash)
|
||
|
throws EcmaScriptException {
|
||
|
//System.err.println(" &&& Getting property '" + propertyName + "'");
|
||
|
|
||
|
// Length property is firsy checked
|
||
|
|
||
|
// First return system or or prototype properties
|
||
|
if (propertyName.equals("length")) {
|
||
|
return new ESNumber((double) colNames.size());
|
||
|
} else if (super.hasProperty(propertyName, hash)) {
|
||
|
return super.getProperty(propertyName, hash);
|
||
|
} else {
|
||
|
if (resultSet == null) {
|
||
|
throw new EcmaScriptException("Attempt to access a released result set");
|
||
|
}
|
||
|
if (!firstRowSeen) {
|
||
|
throw new EcmaScriptException("Attempt to access data before the first row is read");
|
||
|
}
|
||
|
try {
|
||
|
int index = -1; // indicates not a valid index value
|
||
|
try {
|
||
|
char c = propertyName.charAt(0);
|
||
|
if ('0' <= c && c <= '9') {
|
||
|
index = Integer.parseInt(propertyName);
|
||
|
}
|
||
|
} catch (NumberFormatException e) {
|
||
|
} catch (StringIndexOutOfBoundsException e) { // for charAt
|
||
|
}
|
||
|
if (index>=0) {
|
||
|
return getProperty(index);
|
||
|
}
|
||
|
Object o = resultSet.getObject(propertyName);
|
||
|
ESValue value = ESLoader.normalizeValue(o, evaluator);
|
||
|
// System.out.println("&& @VALUE : " + value);
|
||
|
lastError = null;
|
||
|
return value;
|
||
|
} catch (SQLException e) {
|
||
|
// System.err.println("##Cannot get property '" + propertyName + "' " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
}
|
||
|
}
|
||
|
return ESUndefined.theUndefined;
|
||
|
}
|
||
|
|
||
|
public ESValue getProperty(int index)
|
||
|
throws EcmaScriptException {
|
||
|
if (!firstRowSeen) {
|
||
|
throw new EcmaScriptException("Attempt to access data before the first row is read");
|
||
|
}
|
||
|
if (resultSet == null) {
|
||
|
throw new EcmaScriptException("Attempt to access a released result set");
|
||
|
}
|
||
|
try {
|
||
|
Object o = resultSet.getObject(index);
|
||
|
ESValue value = ESLoader.normalizeValue(o, evaluator);
|
||
|
lastError = null;
|
||
|
return value;
|
||
|
} catch (SQLException e) {
|
||
|
// System.err.println("##Cannot get property: " + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
}
|
||
|
return ESUndefined.theUndefined;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Returns an enumerator for the key elements of this object.
|
||
|
*
|
||
|
* @return the enumerator - may have 0 length of coulmn names where not found
|
||
|
*/
|
||
|
public Enumeration getProperties() {
|
||
|
if (resultSet == null) {
|
||
|
return (new Vector()).elements();
|
||
|
}
|
||
|
return colNames.elements();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get all properties (including hidden ones), for the command
|
||
|
* @listall of the interpreter. Include the visible properties of the
|
||
|
* prototype (that is the one added by the user) but not the
|
||
|
* hidden ones of the prototype (otherwise this would list
|
||
|
* all functions for any object).
|
||
|
*
|
||
|
* @return An enumeration of all properties (visible and hidden).
|
||
|
*/
|
||
|
public Enumeration getAllProperties() {
|
||
|
return new Enumeration() {
|
||
|
String [] specialProperties = getSpecialPropertyNames();
|
||
|
int specialEnumerator = 0;
|
||
|
Enumeration props = getProperties(); // all of object properties
|
||
|
String currentKey = null;
|
||
|
int currentHash = 0;
|
||
|
boolean inside = false; // true when examing prototypes properties
|
||
|
public boolean hasMoreElements() {
|
||
|
// OK if we already checked for a property and one exists
|
||
|
if (currentKey != null) return true;
|
||
|
// Loop on special properties first
|
||
|
if (specialEnumerator < specialProperties.length) {
|
||
|
currentKey = specialProperties[specialEnumerator];
|
||
|
currentHash = currentKey.hashCode();
|
||
|
specialEnumerator++;
|
||
|
return true;
|
||
|
}
|
||
|
// loop on standard or prototype properties
|
||
|
while (props.hasMoreElements()) {
|
||
|
currentKey = (String) props.nextElement();
|
||
|
currentHash = currentKey.hashCode();
|
||
|
if (inside) {
|
||
|
try {
|
||
|
if (hasProperty(currentKey, currentHash)) continue;
|
||
|
} catch (EcmaScriptException ignore) {
|
||
|
}
|
||
|
// SHOULD CHECK IF NOT IN SPECIAL
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
// If prototype properties have not yet been examined, look for them
|
||
|
if (!inside && getPrototype() != null) {
|
||
|
inside = true;
|
||
|
props = getPrototype().getProperties();
|
||
|
while (props.hasMoreElements()) {
|
||
|
currentKey = (String) props.nextElement();
|
||
|
currentHash = currentKey.hashCode();
|
||
|
try {
|
||
|
if (hasProperty(currentKey, currentHash)) continue;
|
||
|
} catch (EcmaScriptException ignore) {
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
public Object nextElement() {
|
||
|
if (hasMoreElements()) {
|
||
|
String key = currentKey;
|
||
|
currentKey = null;
|
||
|
return key;
|
||
|
} else {
|
||
|
throw new java.util.NoSuchElementException();
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public String[] getSpecialPropertyNames() {
|
||
|
String [] ns = {"length"};
|
||
|
return ns;
|
||
|
}
|
||
|
|
||
|
|
||
|
ESValue next() throws EcmaScriptException {
|
||
|
boolean status = false;
|
||
|
if (lastRowSeen) {
|
||
|
throw new EcmaScriptException("Attempt to access a next row after last row has been returned");
|
||
|
}
|
||
|
if (resultSet == null) {
|
||
|
throw new EcmaScriptException("Attempt to access a released result set");
|
||
|
}
|
||
|
try {
|
||
|
status = resultSet.next();
|
||
|
lastError = null;
|
||
|
} catch (SQLException e) {
|
||
|
// System.err.println("##Cannot do next:" + e);
|
||
|
// e.printStackTrace();
|
||
|
lastError = e;
|
||
|
}
|
||
|
if (status) firstRowSeen = true;
|
||
|
else lastRowSeen = true;
|
||
|
return ESBoolean.makeBoolean(status);
|
||
|
}
|
||
|
|
||
|
public String toString() {
|
||
|
return "[RowSet: '"+sql+"'" +
|
||
|
(resultSet==null ? " - released]" :
|
||
|
(lastRowSeen ? " - at end]" :
|
||
|
(firstRowSeen ? "]" : " - at start]")));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
public class Database extends Extension {
|
||
|
|
||
|
|
||
|
private transient Evaluator evaluator = null;
|
||
|
private ESObject esDatabasePrototype = null;
|
||
|
private ESObject esRowSetPrototype = null;
|
||
|
|
||
|
public Database () {
|
||
|
super();
|
||
|
}
|
||
|
|
||
|
|
||
|
class GlobalObjectDatabase extends BuiltinFunctionObject {
|
||
|
GlobalObjectDatabase(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
return doConstruct(thisObject, arguments);
|
||
|
}
|
||
|
|
||
|
public ESObject doConstruct(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESDatabase database = null;
|
||
|
//System.out.println("esDatabasePrototype="+esDatabasePrototype);
|
||
|
if (arguments.length==0) {
|
||
|
throw new EcmaScriptException("Database requires 1 or 2 arguments");
|
||
|
} else if (arguments.length==1) {
|
||
|
database = new ESDatabase(esDatabasePrototype,
|
||
|
this.evaluator,
|
||
|
esRowSetPrototype,
|
||
|
arguments[0].toString());
|
||
|
} else if (arguments.length>1) {
|
||
|
database = new ESDatabase(esDatabasePrototype,
|
||
|
this.evaluator,
|
||
|
esRowSetPrototype,
|
||
|
arguments[0].toString(),
|
||
|
arguments[1].toString());
|
||
|
}
|
||
|
return database;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
class DatabaseGetLastError extends BuiltinFunctionObject {
|
||
|
DatabaseGetLastError(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESDatabase database = (ESDatabase) thisObject;
|
||
|
return database.getLastError();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class DatabaseRelease extends BuiltinFunctionObject {
|
||
|
DatabaseRelease(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESDatabase database = (ESDatabase) thisObject;
|
||
|
return database.release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
class DatabaseConnect extends BuiltinFunctionObject {
|
||
|
DatabaseConnect(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESDatabase database = (ESDatabase) thisObject;
|
||
|
return database.connect(arguments);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
class DatabaseDisconnect extends BuiltinFunctionObject {
|
||
|
DatabaseDisconnect(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESDatabase database = (ESDatabase) thisObject;
|
||
|
return database.disconnect();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class DatabaseExecuteRetrieval extends BuiltinFunctionObject {
|
||
|
DatabaseExecuteRetrieval(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESDatabase database = (ESDatabase) thisObject;
|
||
|
return database.executeRetrieval(arguments);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
class DatabaseExecuteCommand extends BuiltinFunctionObject {
|
||
|
DatabaseExecuteCommand(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESDatabase database = (ESDatabase) thisObject;
|
||
|
return database.executeCommand(arguments);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
class DatabaseGetMetaData extends BuiltinFunctionObject {
|
||
|
DatabaseGetMetaData(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESDatabase database = (ESDatabase) thisObject;
|
||
|
return new ESWrapper(database.getMetaData(), this.evaluator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
class RowSetRelease extends BuiltinFunctionObject {
|
||
|
RowSetRelease(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESRowSet rowSet = (ESRowSet) thisObject;
|
||
|
return rowSet.release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class RowSetNext extends BuiltinFunctionObject {
|
||
|
RowSetNext(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESRowSet rowSet = (ESRowSet) thisObject;
|
||
|
return rowSet.next();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class RowSetGetColumnCount extends BuiltinFunctionObject {
|
||
|
RowSetGetColumnCount(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESRowSet rowSet = (ESRowSet) thisObject;
|
||
|
return new ESNumber((double) rowSet.getColumnCount());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class RowSetGetColumnName extends BuiltinFunctionObject {
|
||
|
RowSetGetColumnName(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESRowSet rowSet = (ESRowSet) thisObject;
|
||
|
if (arguments.length<1) {
|
||
|
throw new EcmaScriptException("Missing parameter in function " + this);
|
||
|
}
|
||
|
int idx = arguments[0].toUInt32();
|
||
|
String name = rowSet.getColumnName(idx); // base 1
|
||
|
if (name==null) {
|
||
|
return ESUndefined.theUndefined;
|
||
|
} else {
|
||
|
return new ESString(name);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
class RowSetGetColumnItem extends BuiltinFunctionObject {
|
||
|
RowSetGetColumnItem(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESRowSet rowSet = (ESRowSet) thisObject;
|
||
|
if (arguments.length<1) {
|
||
|
throw new EcmaScriptException("Missing parameter in function " + this);
|
||
|
}
|
||
|
String name = arguments[0].toString();
|
||
|
return rowSet.getColumnItem(name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
class RowSetGetColumnDatatypeNumber extends BuiltinFunctionObject {
|
||
|
RowSetGetColumnDatatypeNumber(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESRowSet rowSet = (ESRowSet) thisObject;
|
||
|
if (arguments.length<1) {
|
||
|
throw new EcmaScriptException("Missing parameter in function " + this);
|
||
|
}
|
||
|
int idx = arguments[0].toUInt32();
|
||
|
return new ESNumber((double)rowSet.getColumnDatatypeNumber(idx));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
class RowSetGetColumnDatatypeName extends BuiltinFunctionObject {
|
||
|
RowSetGetColumnDatatypeName(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESRowSet rowSet = (ESRowSet) thisObject;
|
||
|
if (arguments.length<1) {
|
||
|
throw new EcmaScriptException("Missing parameter in function " + this);
|
||
|
}
|
||
|
int idx = arguments[0].toUInt32();
|
||
|
String name = rowSet.getColumnDatatypeName(idx);
|
||
|
//System.out.println("Datat type name for col " + idx + " is " +name);
|
||
|
if (name==null) {
|
||
|
return ESUndefined.theUndefined;
|
||
|
} else {
|
||
|
return new ESString(name);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
class RowSetHasMoreRows extends BuiltinFunctionObject {
|
||
|
RowSetHasMoreRows(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESRowSet rowSet = (ESRowSet) thisObject;
|
||
|
return ESBoolean.makeBoolean(rowSet.hasMoreRows());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
class RowSetGetMetaData extends BuiltinFunctionObject {
|
||
|
RowSetGetMetaData(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||
|
super(fp, evaluator, name, 1);
|
||
|
}
|
||
|
public ESValue callFunction(ESObject thisObject,
|
||
|
ESValue[] arguments)
|
||
|
throws EcmaScriptException {
|
||
|
ESRowSet rowSet = (ESRowSet) thisObject;
|
||
|
return new ESWrapper(rowSet.getMetaData(), this.evaluator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
public void initializeExtension(Evaluator evaluator) throws EcmaScriptException {
|
||
|
|
||
|
this.evaluator = evaluator;
|
||
|
GlobalObject go = evaluator.getGlobalObject();
|
||
|
ObjectPrototype op = (ObjectPrototype) evaluator.getObjectPrototype();
|
||
|
FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
|
||
|
|
||
|
esRowSetPrototype = new ObjectPrototype(op, evaluator);
|
||
|
esDatabasePrototype = new ESDatabase(op, evaluator); // No driver
|
||
|
|
||
|
ESObject globalDatabaseObject = new GlobalObjectDatabase("Database", evaluator, fp);
|
||
|
globalDatabaseObject.putHiddenProperty("prototype",esDatabasePrototype);
|
||
|
globalDatabaseObject.putHiddenProperty("length",new ESNumber(2));
|
||
|
|
||
|
|
||
|
esDatabasePrototype.putHiddenProperty("constructor",globalDatabaseObject);
|
||
|
esDatabasePrototype.putHiddenProperty("getLastError",
|
||
|
new DatabaseGetLastError("getLastError", evaluator, fp));
|
||
|
esDatabasePrototype.putHiddenProperty("release",
|
||
|
new DatabaseRelease("release", evaluator, fp));
|
||
|
esDatabasePrototype.putHiddenProperty("connect",
|
||
|
new DatabaseConnect("connect", evaluator, fp));
|
||
|
esDatabasePrototype.putHiddenProperty("disconnect",
|
||
|
new DatabaseDisconnect("disconnect", evaluator, fp));
|
||
|
esDatabasePrototype.putHiddenProperty("executeRetrieval",
|
||
|
new DatabaseExecuteRetrieval("executeRetrieval", evaluator, fp));
|
||
|
esDatabasePrototype.putHiddenProperty("executeCommand",
|
||
|
new DatabaseExecuteCommand("executeCommand", evaluator, fp));
|
||
|
esDatabasePrototype.putHiddenProperty("getMetaData",
|
||
|
new DatabaseGetMetaData("getMetaData", evaluator, fp));
|
||
|
|
||
|
esRowSetPrototype.putHiddenProperty("release",
|
||
|
new RowSetRelease("release", evaluator, fp));
|
||
|
esRowSetPrototype.putHiddenProperty("next",
|
||
|
new RowSetNext("next", evaluator, fp));
|
||
|
esRowSetPrototype.putHiddenProperty("getColumnCount",
|
||
|
new RowSetGetColumnCount("getColumnCount", evaluator, fp));
|
||
|
esRowSetPrototype.putHiddenProperty("getColumnName",
|
||
|
new RowSetGetColumnName("getColumnName", evaluator, fp));
|
||
|
esRowSetPrototype.putHiddenProperty("getColumnItem",
|
||
|
new RowSetGetColumnItem("getColumnItem", evaluator, fp));
|
||
|
esRowSetPrototype.putHiddenProperty("getColumnDatatypeNumber",
|
||
|
new RowSetGetColumnDatatypeNumber("getColumnDatatypeNumber", evaluator, fp));
|
||
|
esRowSetPrototype.putHiddenProperty("getColumnDatatypeName",
|
||
|
new RowSetGetColumnDatatypeName("getColumnDatatypeName", evaluator, fp));
|
||
|
esRowSetPrototype.putHiddenProperty("hasMoreRows",
|
||
|
new RowSetHasMoreRows("hasMoreRows", evaluator, fp));
|
||
|
esRowSetPrototype.putHiddenProperty("getMetaData",
|
||
|
new RowSetGetMetaData("getMetaData", evaluator, fp));
|
||
|
|
||
|
go.putHiddenProperty("Database", globalDatabaseObject);
|
||
|
}
|
||
|
}
|