teiid SVN: r3382 - in trunk: client/src/main/java/org/teiid and 20 other directories.
by teiid-commits@lists.jboss.org
Author: rareddy
Date: 2011-08-15 14:31:49 -0400 (Mon, 15 Aug 2011)
New Revision: 3382
Added:
trunk/client/src/main/java/org/teiid/gss/
trunk/client/src/main/java/org/teiid/gss/GSSCallbackHandler.java
trunk/client/src/main/java/org/teiid/gss/MakeGSS.java
trunk/jboss-integration/src/main/java/org/teiid/jboss/AssosiateCallerIdentityLoginModule.java
Modified:
trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml
trunk/client/src/main/java/org/teiid/client/security/ILogon.java
trunk/client/src/main/java/org/teiid/client/security/LogonResult.java
trunk/client/src/main/java/org/teiid/jdbc/JDBCURL.java
trunk/client/src/main/java/org/teiid/jdbc/TeiidDataSource.java
trunk/client/src/main/java/org/teiid/net/TeiidURL.java
trunk/client/src/main/java/org/teiid/net/socket/SocketServerConnection.java
trunk/client/src/main/resources/org/teiid/jdbc/i18n.properties
trunk/client/src/test/java/org/teiid/jdbc/TestTeiidDriver.java
trunk/client/src/test/java/org/teiid/net/socket/TestSocketServerConnection.java
trunk/documentation/admin-guide/src/main/docbook/en-US/content/security.xml
trunk/documentation/client-developers-guide/src/main/docbook/en-US/content/jdbc-connection.xml
trunk/engine/src/main/java/org/teiid/dqp/service/SessionService.java
trunk/jboss-integration/src/main/java/org/teiid/jboss/deployers/RuntimeEngineDeployer.java
trunk/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java
trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemote.java
trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java
trunk/runtime/src/main/java/org/teiid/services/SessionServiceImpl.java
trunk/runtime/src/main/java/org/teiid/services/TeiidLoginContext.java
trunk/runtime/src/main/java/org/teiid/transport/LogonImpl.java
trunk/runtime/src/main/java/org/teiid/transport/ODBCClientInstance.java
trunk/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java
trunk/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java
trunk/runtime/src/main/java/org/teiid/transport/PgFrontendProtocol.java
trunk/runtime/src/main/resources/org/teiid/runtime/i18n.properties
trunk/runtime/src/test/java/org/teiid/transport/TestLogonImpl.java
trunk/runtime/src/test/java/org/teiid/transport/TestSocketRemoting.java
trunk/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java
trunk/test-integration/pom.xml
Log:
TEIID-1610: Implementing the GSSAPI support for remote JDBC & ODBC clients in Teiid
Modified: trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml
===================================================================
--- trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml 2011-08-15 18:31:49 UTC (rev 3382)
@@ -13,6 +13,10 @@
<property name="sessionMaxLimit">5000</property>
<!-- Max allowed time before the session is terminated by the system, 0 indicates unlimited (default 0) -->
<property name="sessionExpirationTimeLimit">0</property>
+ <!-- authentication type are CLEARTEXT, KRB5 (default:CLEARTEXT) -->
+ <property name="authenticationType">CLEARTEXT</property>
+ <!-- When authenticationType=KRB5, then it requires a kerberos security domain to authorize first before teiid-security takes over -->
+ <property name="krb5SecurityDomain">teiid-krb5</property>
</bean>
<bean name="BufferService" class="org.teiid.services.BufferServiceImpl">
@@ -256,10 +260,36 @@
<property name="authenticationMode">1-way</property>
</bean>
- <!-- teiid's default security domain, replace this with your own if needs to be any other JAAS domain -->
+ <!-- un-comment and edit for Kerberos login configuration (comment the original login config below)
+ <application-policy xmlns="urn:jboss:security-beans:1.0" name="teiid-krb5">
+ <authentication>
+ <login-module code="com.sun.security.auth.module.Krb5LoginModule" flag="required">
+ <module-option name="storeKey">true</module-option>
+ <module-option name="useKeyTab">true</module-option>
+ <module-option name="principal">demo(a)EXAMPLE.COM</module-option>
+ <module-option name="keyTab">/path/to/krb5.keytab</module-option>
+ <module-option name="doNotPrompt">true</module-option>
+ <module-option name="debug">true</module-option>
+ </login-module>
+ </authentication>
+ </application-policy>
+
<application-policy xmlns="urn:jboss:security-beans:1.0" name="teiid-security">
<authentication>
+ <login-module code="org.teiid.jboss.AssosiateCallerIdentityLoginModule" flag="required"/>
<login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
+ <module-option name="password-stacking">useFirstPass</module-option>
+ <module-option name="usersProperties">props/teiid-security-users.properties</module-option>
+ <module-option name="rolesProperties">props/teiid-security-roles.properties</module-option>
+ </login-module>
+ </authentication>
+ </application-policy>
+
+ -->
+ <!-- teiid's default security domain, replace this with your own if needs to be any other JAAS domain -->
+ <application-policy xmlns="urn:jboss:security-beans:1.0" name="teiid-security">
+ <authentication>
+ <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
<!-- property files can found under conf/props directory -->
<module-option name="usersProperties">props/teiid-security-users.properties</module-option>
<module-option name="rolesProperties">props/teiid-security-roles.properties</module-option>
Modified: trunk/client/src/main/java/org/teiid/client/security/ILogon.java
===================================================================
--- trunk/client/src/main/java/org/teiid/client/security/ILogon.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/client/src/main/java/org/teiid/client/security/ILogon.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -34,9 +34,14 @@
* Generic logon interface.
*/
public interface ILogon {
+ static final String KRB5TOKEN = "KRB5TOKEN"; //$NON-NLS-1$
+ static final String KRB5_ESTABLISHED = "KRB5_CONTEXT_ESTABLISHED"; //$NON-NLS-1$
+
LogonResult logon(Properties connectionProperties)
throws LogonException, TeiidComponentException, CommunicationException;
-
+
+ LogonResult neogitiateGssLogin(Properties connectionProperties, byte[] serviceToken, boolean createSession) throws LogonException;
+
/**
* Ping the server to see if the client-server connection is alive.
* @throws InvalidSessionException if the sessionID is invalid
Modified: trunk/client/src/main/java/org/teiid/client/security/LogonResult.java
===================================================================
--- trunk/client/src/main/java/org/teiid/client/security/LogonResult.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/client/src/main/java/org/teiid/client/security/LogonResult.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -26,10 +26,14 @@
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
+import java.util.HashMap;
+import java.util.Map;
import java.util.TimeZone;
+import org.teiid.core.util.ExternalizeUtil;
+
/**
* Dataholder for the result of <code>ILogon.logon()</code>.
* Contains a sessionID
@@ -44,8 +48,9 @@
private SessionToken sessionToken;
private String vdbName;
private int vdbVersion;
+ private Map<Object, Object> addtionalProperties;
- public LogonResult() {
+ public LogonResult() {
}
public LogonResult(SessionToken token, String vdbName, int vdbVersion, String clusterName) {
@@ -89,6 +94,20 @@
return vdbVersion;
}
+ public Object getProperty(String key) {
+ if (this.addtionalProperties == null) {
+ return null;
+ }
+ return addtionalProperties.get(key);
+ }
+
+ public void addProperty(String key, Object value) {
+ if (this.addtionalProperties == null) {
+ this.addtionalProperties = new HashMap<Object, Object>();
+ }
+ this.addtionalProperties.put(key, value);
+ }
+
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
@@ -97,6 +116,7 @@
timeZone = (TimeZone)in.readObject();
clusterName = (String)in.readObject();
vdbVersion = in.readInt();
+ addtionalProperties = ExternalizeUtil.readMap(in);
}
@Override
@@ -106,6 +126,7 @@
out.writeObject(timeZone);
out.writeObject(clusterName);
out.writeInt(vdbVersion);
+ ExternalizeUtil.writeMap(out, addtionalProperties);
}
}
Added: trunk/client/src/main/java/org/teiid/gss/GSSCallbackHandler.java
===================================================================
--- trunk/client/src/main/java/org/teiid/gss/GSSCallbackHandler.java (rev 0)
+++ trunk/client/src/main/java/org/teiid/gss/GSSCallbackHandler.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -0,0 +1,85 @@
+/*-------------------------------------------------------------------------
+*
+* Copyright (c) 2008, PostgreSQL Global Development Group
+*
+* IDENTIFICATION
+* $PostgreSQL: pgjdbc/org/postgresql/gss/GSSCallbackHandler.java,v 1.2 2008/11/29 07:43:47 jurka Exp $
+*
+*-------------------------------------------------------------------------
+*/
+
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ *
+ * This library 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.
+ *
+ * This library 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 org.teiid.gss;
+
+import java.io.IOException;
+import javax.security.auth.callback.*;
+
+import org.teiid.jdbc.JDBCPlugin;
+
+public class GSSCallbackHandler implements CallbackHandler {
+
+ private final String user;
+ private final String password;
+
+ public GSSCallbackHandler(String user, String password)
+ {
+ this.user = user;
+ this.password = password;
+ }
+
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
+ {
+ for (int i=0; i<callbacks.length; i++) {
+ if (callbacks[i] instanceof TextOutputCallback) {
+ TextOutputCallback toc = (TextOutputCallback)callbacks[i];
+ switch (toc.getMessageType()) {
+ case TextOutputCallback.INFORMATION:
+ System.out.println("INFO: " + toc.getMessage());//$NON-NLS-1$
+ break;
+ case TextOutputCallback.ERROR:
+ System.out.println("ERROR: " + toc.getMessage()); //$NON-NLS-1$
+ break;
+ case TextOutputCallback.WARNING:
+ System.out.println("WARNING: " + toc.getMessage());//$NON-NLS-1$
+ break;
+ default:
+ throw new IOException("Unsupported message type: " + toc.getMessageType()); //$NON-NLS-1$
+ }
+ } else if (callbacks[i] instanceof NameCallback) {
+ NameCallback nc = (NameCallback)callbacks[i];
+ nc.setName(user);
+ } else if (callbacks[i] instanceof PasswordCallback) {
+ PasswordCallback pc = (PasswordCallback)callbacks[i];
+ if (password == null) {
+ throw new IOException(JDBCPlugin.Util.getString("no_krb_ticket")); //$NON-NLS-1$
+ }
+ pc.setPassword(password.toCharArray());
+ } else {
+ throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback"); //$NON-NLS-1$
+ }
+ }
+ }
+
+}
+
+
Property changes on: trunk/client/src/main/java/org/teiid/gss/GSSCallbackHandler.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: trunk/client/src/main/java/org/teiid/gss/MakeGSS.java
===================================================================
--- trunk/client/src/main/java/org/teiid/gss/MakeGSS.java (rev 0)
+++ trunk/client/src/main/java/org/teiid/gss/MakeGSS.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -0,0 +1,163 @@
+/*-------------------------------------------------------------------------
+*
+* Copyright (c) 2008, PostgreSQL Global Development Group
+*
+* IDENTIFICATION
+* $PostgreSQL: pgjdbc/org/postgresql/gss/MakeGSS.java,v 1.2.2.1 2009/08/18 03:37:08 jurka Exp $
+*
+*-------------------------------------------------------------------------
+*/
+
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ *
+ * This library 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.
+ *
+ * This library 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 org.teiid.gss;
+
+import java.security.PrivilegedAction;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.teiid.client.security.ILogon;
+import org.teiid.client.security.LogonException;
+import org.teiid.client.security.LogonResult;
+import org.teiid.core.TeiidComponentException;
+import org.teiid.jdbc.JDBCPlugin;
+import org.teiid.jdbc.TeiidSQLException;
+import org.teiid.net.CommunicationException;
+import org.teiid.net.TeiidURL;
+
+
+
+public class MakeGSS {
+
+ private static Logger logger = Logger.getLogger("org.teiid.jdbc"); //$NON-NLS-1$
+
+ public static LogonResult authenticate(ILogon logon, Properties props)
+ throws LogonException, TeiidComponentException, CommunicationException {
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("GSS Authentication Request"); //$NON-NLS-1$
+ }
+
+ Object result = null;
+
+ String jaasApplicationName = props.getProperty(TeiidURL.CONNECTION.JAAS_NAME, "teiid"); //$NON-NLS-1$
+ String kerberosPrincipalName = props.getProperty(TeiidURL.CONNECTION.KERBEROS_SERVICE_PRINCIPLE_NAME, "teiid"); //$NON-NLS-1$
+ String user = props.getProperty(TeiidURL.CONNECTION.USER_NAME);
+ String password = props.getProperty(TeiidURL.CONNECTION.PASSWORD);
+
+ try {
+ LoginContext lc = new LoginContext(jaasApplicationName, new GSSCallbackHandler(user, password));
+ lc.login();
+
+ Subject sub = lc.getSubject();
+ PrivilegedAction action = new GssAction(logon, kerberosPrincipalName, props);
+ result = Subject.doAs(sub, action);
+ } catch (Exception e) {
+ throw new LogonException(e, JDBCPlugin.Util.getString("gss_auth_failed")); //$NON-NLS-1$
+ }
+
+ if (result instanceof LogonException)
+ throw (LogonException)result;
+ else if (result instanceof TeiidComponentException)
+ throw (TeiidComponentException)result;
+ else if (result instanceof CommunicationException)
+ throw (CommunicationException)result;
+ else if (result instanceof Exception)
+ throw new LogonException((Exception)result, JDBCPlugin.Util.getString("gss_auth_failed")); //$NON-NLS-1$
+
+ return (LogonResult)result;
+ }
+
+}
+
+class GssAction implements PrivilegedAction {
+
+ private static Logger logger = Logger.getLogger("org.teiid.jdbc"); //$NON-NLS-1$
+ private final ILogon logon;
+ private final String kerberosPrincipalName;
+ private Properties props;
+
+ public GssAction(ILogon pgStream, String kerberosPrincipalName, Properties props) {
+ this.logon = pgStream;
+ this.kerberosPrincipalName = kerberosPrincipalName;
+ this.props = props;
+ }
+
+ public Object run() {
+ byte outToken[] = null;
+
+ try {
+ org.ietf.jgss.Oid desiredMechs[] = new org.ietf.jgss.Oid[1];
+ desiredMechs[0] = new org.ietf.jgss.Oid("1.2.840.113554.1.2.2"); //$NON-NLS-1$
+
+ GSSManager manager = GSSManager.getInstance();
+
+ // null on second param means the serverName is already in the native format.
+ GSSName serverName = manager.createName(this.kerberosPrincipalName, null);
+
+ GSSContext secContext = manager.createContext(serverName, desiredMechs[0], null, GSSContext.DEFAULT_LIFETIME);
+ secContext.requestMutualAuth(true);
+ secContext.requestConf(true); // Will use confidentiality later
+ secContext.requestInteg(true); // Will use integrity later
+
+ byte inToken[] = new byte[0];
+
+ boolean established = false;
+ LogonResult result = null;
+ while (!established) {
+ outToken = secContext.initSecContext(inToken, 0, inToken.length);
+ if (outToken != null) {
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("Sending Service Token to Server (GSS Authentication Token)"); //$NON-NLS-1$
+ }
+ result = logon.neogitiateGssLogin(this.props, outToken, true);
+ inToken = (byte[])result.getProperty(ILogon.KRB5TOKEN);
+ }
+
+ if (!secContext.isEstablished()) {
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("Authentication GSS Continue"); //$NON-NLS-1$
+ }
+ } else {
+ established = true;
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("Authentication GSS Established"); //$NON-NLS-1$
+ }
+ }
+ }
+ return result;
+ } catch (GSSException gsse) {
+ return TeiidSQLException.create(gsse, JDBCPlugin.Util.getString("gss_auth_failed")); //$NON-NLS-1$
+ } catch(Exception e) {
+ return e;
+ }
+ }
+}
+
Property changes on: trunk/client/src/main/java/org/teiid/gss/MakeGSS.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Modified: trunk/client/src/main/java/org/teiid/jdbc/JDBCURL.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/JDBCURL.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/client/src/main/java/org/teiid/jdbc/JDBCURL.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -73,7 +73,10 @@
BaseDataSource.PASSWORD,
TeiidURL.CONNECTION.AUTO_FAILOVER,
TeiidURL.CONNECTION.DISCOVERY_STRATEGY,
- TeiidURL.CONNECTION.PASSTHROUGH_AUTHENTICATION));
+ TeiidURL.CONNECTION.PASSTHROUGH_AUTHENTICATION,
+ TeiidURL.CONNECTION.AUTHENTICATION_TYPE,
+ TeiidURL.CONNECTION.JAAS_NAME,
+ TeiidURL.CONNECTION.KERBEROS_SERVICE_PRINCIPLE_NAME));
props.addAll(EXECUTION_PROPERTIES);
return Collections.unmodifiableSet(props);
}
Modified: trunk/client/src/main/java/org/teiid/jdbc/TeiidDataSource.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/TeiidDataSource.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/client/src/main/java/org/teiid/jdbc/TeiidDataSource.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -98,7 +98,21 @@
*/
private boolean passthroughAuthentication = false;
-
+ /**
+ * Authentication type to used from client. choices are simple - which is plain user/password; krb5 - kerberos
+ */
+ private String authenticationType;
+
+ /**
+ * Name of the jass configuration to use from the -Djava.security.auth.login.config=login.conf property
+ */
+ private String jaasName;
+
+ /**
+ * Name of Kerberos KDC service principle name
+ */
+ private String kerberosServicePrincipleName;
+
public TeiidDataSource() {
}
@@ -243,6 +257,16 @@
private Properties buildEmbeddedProperties(final String userName, final String password) {
Properties props = buildProperties(userName, password);
props.setProperty(TeiidURL.CONNECTION.PASSTHROUGH_AUTHENTICATION, Boolean.toString(this.passthroughAuthentication));
+
+ if (getAuthenticationType() != null) {
+ props.setProperty(TeiidURL.CONNECTION.AUTHENTICATION_TYPE, getAuthenticationType());
+ }
+ if (getJaasName() != null) {
+ props.setProperty(TeiidURL.CONNECTION.JAAS_NAME, getJaasName());
+ }
+ if (getKerberosServicePrincipleName() != null) {
+ props.setProperty(TeiidURL.CONNECTION.KERBEROS_SERVICE_PRINCIPLE_NAME, getKerberosServicePrincipleName());
+ }
return props;
}
@@ -466,6 +490,57 @@
*/
public void setPassthroughAuthentication(final boolean passthroughAuthentication) {
this.passthroughAuthentication = passthroughAuthentication;
- }
+ }
+
+ /**
+ * Authentication Type {simple, krb5} default:simple
+ * @return
+ */
+ public String getAuthenticationType() {
+ return authenticationType;
+ }
+
+ /**
+ * Authentication Type.
+ * @since 7.6
+ * @return
+ */
+ public void setAuthenticationType(final String authType) {
+ this.authenticationType = authType;
+ }
+
+ /**
+ * Application name from JAAS Login Config file
+ * @since 7.6
+ * @return
+ */
+ public String getJaasName() {
+ return jaasName;
+ }
+
+ /**
+ * Application name from JAAS Login Config file
+ * @since 7.6
+ */
+ public void setJaasName(String jaasApplicationName) {
+ this.jaasName = jaasApplicationName;
+ }
+
+ /**
+ * Kerberos KDC service principle name
+ * @since 7.6
+ * @return
+ */
+ public String getKerberosServicePrincipleName() {
+ return kerberosServicePrincipleName;
+ }
+
+ /**
+ * Kerberos KDC service principle name
+ * @since 7.6
+ */
+ public void setKerberosServicePrincipleName(String kerberosServerName) {
+ this.kerberosServicePrincipleName = kerberosServerName;
+ }
}
Modified: trunk/client/src/main/java/org/teiid/net/TeiidURL.java
===================================================================
--- trunk/client/src/main/java/org/teiid/net/TeiidURL.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/client/src/main/java/org/teiid/net/TeiidURL.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -82,6 +82,16 @@
public static final String ADMIN = "admin"; //$NON-NLS-1$
public static final String PASSTHROUGH_AUTHENTICATION = "PassthroughAuthentication"; //$NON-NLS-1$
+
+ public static final String AUTHENTICATION_TYPE = "authenticationType"; //$NON-NLS-1$
+
+ public static final String JAAS_NAME = "jaasName"; //$NON-NLS-1$
+
+ public static final String KERBEROS_SERVICE_PRINCIPLE_NAME = "kerberosServicePrincipleName"; //$NON-NLS-1$
+
+ public enum AuthenticationType {
+ CLEARTEXT,KRB5
+ };
}
public static final String DOT_DELIMITER = "."; //$NON-NLS-1$
Modified: trunk/client/src/main/java/org/teiid/net/socket/SocketServerConnection.java
===================================================================
--- trunk/client/src/main/java/org/teiid/net/socket/SocketServerConnection.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/client/src/main/java/org/teiid/net/socket/SocketServerConnection.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -49,12 +49,14 @@
import org.teiid.client.util.ResultsFuture;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidException;
+import org.teiid.gss.MakeGSS;
import org.teiid.jdbc.JDBCPlugin;
import org.teiid.net.CommunicationException;
import org.teiid.net.ConnectionException;
import org.teiid.net.HostInfo;
import org.teiid.net.ServerConnection;
import org.teiid.net.TeiidURL;
+import org.teiid.net.TeiidURL.CONNECTION.AuthenticationType;
/**
@@ -166,8 +168,18 @@
private void logon(ILogon newLogon, boolean logoff) throws LogonException,
TeiidComponentException, CommunicationException {
- LogonResult newResult = newLogon.logon(connProps);
+
SocketServerInstance instance = this.serverInstance;
+ LogonResult newResult = null;
+
+ AuthenticationType authType = getAuthenticationType();
+ if (AuthenticationType.CLEARTEXT.equals(authType)) {
+ newResult = newLogon.logon(connProps);
+ }
+ else if (AuthenticationType.KRB5.equals(authType)) {
+ newResult = MakeGSS.authenticate(newLogon, connProps);
+ }
+
if (logoff) {
if ("7.3".compareTo(this.serverInstance.getServerVersion()) <= 0) { //$NON-NLS-1$
//just remove the current instance - the server has already logged off the current user
@@ -176,10 +188,19 @@
}
logoffAll();
}
+
this.logonResult = newResult;
this.logonResults.put(instance.getHostInfo(), this.logonResult);
this.connectionFactory.connected(instance, this.logonResult.getSessionToken());
}
+
+ private AuthenticationType getAuthenticationType() {
+ String authStr = this.connProps.getProperty(TeiidURL.CONNECTION.AUTHENTICATION_TYPE);
+ if (authStr == null) {
+ return AuthenticationType.CLEARTEXT;
+ }
+ return AuthenticationType.valueOf(authStr);
+ }
private ILogon connect(HostInfo hostInfo) throws CommunicationException,
IOException {
Modified: trunk/client/src/main/resources/org/teiid/jdbc/i18n.properties
===================================================================
--- trunk/client/src/main/resources/org/teiid/jdbc/i18n.properties 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/client/src/main/resources/org/teiid/jdbc/i18n.properties 2011-08-15 18:31:49 UTC (rev 3382)
@@ -150,3 +150,8 @@
TeiidURL.port_out_of_range=The port ''{0}'' is out of range.
BatchSerializer.datatype_mismatch=The modeled datatype {0} for column {1} doesn''t match the runtime type "{2}". Please ensure that the column''s modeled datatype matches the expected data.
+
+
+no_krb_ticket=No cached kerberos ticket found and/or no password supplied
+gss_auth_failed=GSS Authentication failed
+setup_failed=Protocol error. Session setup failed.
Modified: trunk/client/src/test/java/org/teiid/jdbc/TestTeiidDriver.java
===================================================================
--- trunk/client/src/test/java/org/teiid/jdbc/TestTeiidDriver.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/client/src/test/java/org/teiid/jdbc/TestTeiidDriver.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -138,7 +138,7 @@
@Test public void testGetPropertyInfo1() throws Exception {
DriverPropertyInfo info[] = drv.getPropertyInfo("jdbc:teiid:vdb@mm://localhost:12345;applicationName=x", null); //$NON-NLS-1$
- assertEquals(21, info.length);
+ assertEquals(24, info.length);
assertEquals(false, info[0].required);
assertEquals("ApplicationName", info[0].name); //$NON-NLS-1$
assertEquals("x", info[0].value); //$NON-NLS-1$
Modified: trunk/client/src/test/java/org/teiid/net/socket/TestSocketServerConnection.java
===================================================================
--- trunk/client/src/test/java/org/teiid/net/socket/TestSocketServerConnection.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/client/src/test/java/org/teiid/net/socket/TestSocketServerConnection.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -107,6 +107,12 @@
throws TeiidComponentException, CommunicationException {
return ping();
}
+
+ @Override
+ public LogonResult neogitiateGssLogin(Properties connectionProperties,
+ byte[] serviceToken, boolean createSession) throws LogonException {
+ return null;
+ }
}
/**
Modified: trunk/documentation/admin-guide/src/main/docbook/en-US/content/security.xml
===================================================================
--- trunk/documentation/admin-guide/src/main/docbook/en-US/content/security.xml 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/documentation/admin-guide/src/main/docbook/en-US/content/security.xml 2011-08-15 18:31:49 UTC (rev 3382)
@@ -102,6 +102,115 @@
If you want write your own Custom Login module, check out the Developer's Guide for instructions.
</para>
</section>
+
+ <section>
+ <title>Kerberos support through GSSAPI</title>
+ <para>Teiid supports kerberos authentication using GSSAPI, to be used with single sign-on applications.
+ This service ticket negotiation based authentication is supported through remote JDBC and ODBC drivers and as
+ well as in LocalConnections. However, configuration is varies for local connections vs remote connections</para>
+
+ <section>
+ <title>LocalConnection</title>
+ <para>For supporting kerberos through local connections, provide JDBC URL property <emphasis>PassthroughAuthentication</emphasis>
+ as true and use the <ulink url="http://community.jboss.org/docs/DOC-10680">JBoss Negotiation</ulink> as
+ authentication configure your web-application for kerberos. When the web application authenticates with the provided
+ kerberos token, the same subject authenticated will be used in Teiid. For details about configuration, check the
+ JBoss Negotiation documentation.</para>
+ </section>
+
+ <section>
+ <title>Remote JDBC Connection</title>
+ <para>Server: For supporting the kerberos through jdbc from a remote client application, follow the below configuration.
+ On the server, edit "{jboss-as}/server/{profile}/deploy/teiid/teiid-jboss-beans.xml" file, and make sure under
+ "SessionService" bean definition the following properties are set.
+ <programlisting><![CDATA[
+ <!-- Sets the authentication Type -->
+ <property name="authenticationType">KRB5</property>
+ <!-- Security domain used for kerberos authentication -->
+ <property name="krb5SecurityDomain">teiid-krb5</property>
+ ]]></programlisting>
+
+ Now we need to define security domain context for kerberos with name mentioned in above, and since the kerberos
+ authorization can not define authorization roles, we need devise a way to define them using another login context.
+ Given below is sample configuration to define roles using UserRolesLoginModule.
+ Note that the below configuration replaces the default Teiid login configuration. Note to change the principal
+ and key tab locations accordingly.
+
+ <programlisting><![CDATA[
+ <!--login module that negotiates the login conext for kerberos -->
+ <application-policy xmlns="urn:jboss:security-beans:1.0" name="teiid-krb5">
+ <authentication>
+ <login-module code="com.sun.security.auth.module.Krb5LoginModule" flag="required">
+ <module-option name="storeKey">true</module-option>
+ <module-option name="useKeyTab">true</module-option>
+ <module-option name="principal">demo(a)EXAMPLE.COM</module-option>
+ <module-option name="keyTab">path/to/krb5.keytab</module-option>
+ <module-option name="doNotPrompt">true</module-option>
+ <module-option name="debug">false</module-option>
+ </login-module>
+ </authentication>
+ </application-policy>
+
+ <!-- teiid's default security domain, replace this with your own if needs to be any other JAAS domain -->
+ <application-policy xmlns="urn:jboss:security-beans:1.0" name="teiid-security">
+ <authentication>
+ <!-- This module assosiates kerberos user with this login set of login modules -->
+ <login-module code="org.teiid.jboss.AssosiateCallerIdentityLoginModule" flag="required"/>
+ <!-- Login module used for defining roles for user authencated using kerberos, keep the users file empty
+ but provide roles in the roles file for users -->
+ <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
+ <module-option name="password-stacking">useFirstPass</module-option>
+ <module-option name="usersProperties">props/teiid-security-users.properties</module-option>
+ <module-option name="rolesProperties">props/teiid-security-roles.properties</module-option>
+ </login-module>
+ </authentication>
+ </application-policy>
+ ]]></programlisting>
+ Edit "run.conf" or "run.conf.bat"file depending upon the environment in "${jboss-as}/bin" directory
+ and add the following JVM options to startup script (note to change the realm and KDC settings according to your environment)
+ <programlisting><![CDATA[
+ JAVA_OPTS = "$JAVA_OPTS -Djava.security.krb5.realm=EXAMPLE.COM -Djava.security.krb5.kdc=kerberos.example.com -Djavax.security.auth.useSubjectCredsOnly=false"
+ ]]></programlisting>
+ This finishes the configuration on the server side, restart the server and make sure that there were no errors during startup.
+ </para>
+
+ <para>Client: The following configuration needs to be done on the Teiid client application VM. For client VM, JAAS
+ configuration for kerberos authentication needs to be written. A sample configuration file (client.conf) is show below
+
+ <programlisting><![CDATA[
+ Client {
+ com.sun.security.auth.module.Krb5LoginModule required
+ useTicketCache=true
+ storeKey=true
+ useKeyTab=true
+ keyTab="/path/to/krb5.keytab"
+ doNotPrompt=false
+ debug=false
+ principal="demo(a)EXAMPLE.COM";
+ };
+ ]]></programlisting>
+
+ Add the following JVM options to your client's startup script, note the change Realm and KDC settings according to
+ your environment
+ <programlisting><![CDATA[
+ -Djava.security.krb5.realm=EXAMPLE.COM
+ -Djava.security.krb5.kdc=kerberos.example.com
+ -Djavax.security.auth.useSubjectCredsOnly=false
+ -Dsun.security.krb5.debug=false
+ -Djava.security.auth.login.config=/path/to/client.conf
+ ]]></programlisting>
+
+ Add the following URL connection properties to Teiid JDBC connection string
+ <programlisting><![CDATA[
+ authenticationType=KRB5;jaasName=Client;kerberosServicePrincipleName=demo(a)EXAMPLE.COM
+ ]]></programlisting>
+ There is no need to provide the user name and password, when the application is trying to make JDBC connection it
+ will authenticate locally and use the same user credetinals to neogitiate service token with server and grant the
+ connection. See Client Developer's guide for information on connection properties and how to configure data sources.
+ </para>
+ </section>
+
+ </section>
<section>
<title>Security at Data Source level</title>
Modified: trunk/documentation/client-developers-guide/src/main/docbook/en-US/content/jdbc-connection.xml
===================================================================
--- trunk/documentation/client-developers-guide/src/main/docbook/en-US/content/jdbc-connection.xml 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/documentation/client-developers-guide/src/main/docbook/en-US/content/jdbc-connection.xml 2011-08-15 18:31:49 UTC (rev 3382)
@@ -255,7 +255,45 @@
backwards compatibility when JDBC3 and older support is still required. Defaults to true.
</para>
</entry>
- </row>
+ </row>
+ <row>
+ <entry>
+ <code>authenticationType</code>
+ </entry>
+ <entry>
+ <code>String</code>
+ </entry>
+ <entry>
+ <para>Type of authentication to use. Valid values are CLEARTEXT (default) and KRB5 (kerberos). See
+ Admin Guide for configuration required for kerberos
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <code>jaasName</code>
+ </entry>
+ <entry>
+ <code>String</code>
+ </entry>
+ <entry>
+ <para>JAAS configuration name. Only applies when configuring a kerberos authentication.
+ See Admin Guide for configuration required for kerberos</para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <code>kerberosServicePrincipleName</code>
+ </entry>
+ <entry>
+ <code>String</code>
+ </entry>
+ <entry>
+ <para>Kerberos authenticated principle name. Only applies when configuring a kerberos authentication.
+ See Admin Guide for configuration required for kerberos</para>
+ </entry>
+ </row>
+
</tbody>
</tgroup>
</table>
Modified: trunk/engine/src/main/java/org/teiid/dqp/service/SessionService.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/service/SessionService.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/engine/src/main/java/org/teiid/dqp/service/SessionService.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -23,13 +23,17 @@
package org.teiid.dqp.service;
import java.util.Collection;
+import java.util.List;
import java.util.Properties;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.teiid.adminapi.impl.SessionMetadata;
import org.teiid.client.security.InvalidSessionException;
import org.teiid.dqp.internal.process.DQPCore;
+import org.teiid.net.TeiidURL.CONNECTION.AuthenticationType;
import org.teiid.security.Credentials;
@@ -138,5 +142,12 @@
SessionMetadata getActiveSession(String sessionID);
void setDqp(DQPCore dqp);
+
+ LoginContext createLoginContext(String securityDomain, String user, String password) throws LoginException;
+ AuthenticationType getAuthType();
+
+ String getKrb5SecurityDomain();
+
+ void assosiateSubjectInContext(String securityDomain, Subject subject);
}
Added: trunk/jboss-integration/src/main/java/org/teiid/jboss/AssosiateCallerIdentityLoginModule.java
===================================================================
--- trunk/jboss-integration/src/main/java/org/teiid/jboss/AssosiateCallerIdentityLoginModule.java (rev 0)
+++ trunk/jboss-integration/src/main/java/org/teiid/jboss/AssosiateCallerIdentityLoginModule.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -0,0 +1,87 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2007, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This 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.
+ *
+ * This software 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 software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.teiid.jboss;
+
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+
+import org.jboss.security.SecurityContext;
+import org.jboss.security.SubjectInfo;
+import org.jboss.security.auth.spi.AbstractServerLoginModule;
+
+/**
+ * This login modules simply takes the subject in the current context and adds
+ * its principle to shared state. This is same as CallerIdentityLoginModule,
+ * just it does not extend the AbstractPasswordCredentialLoginModule
+ */
+public class AssosiateCallerIdentityLoginModule extends AbstractServerLoginModule {
+
+ private Principal principal;
+
+ public void initialize(Subject subject, CallbackHandler handler,
+ Map sharedState, Map options) {
+ super.initialize(subject, handler, sharedState, options);
+ }
+
+ /**
+ * Performs the login association between the caller and the resource for a
+ * 1 to 1 mapping. This acts as a login propagation strategy and is useful
+ * for single-sign on requirements
+ *
+ * @return True if authentication succeeds
+ * @throws LoginException
+ */
+ public boolean login() throws LoginException {
+
+ SecurityContext sc = SecurityActions.getSecurityContext();
+ SubjectInfo si = sc.getSubjectInfo();
+ Subject subject = si.getAuthenticatedSubject();
+
+ Set<Principal> principals = subject.getPrincipals();
+ this.principal = principals.iterator().next();
+
+ if (super.login() == true) {
+ return true;
+ }
+
+ // Put the principal name into the sharedState map
+ sharedState.put("javax.security.auth.login.name", principal.getName()); //$NON-NLS-1$
+ sharedState.put("javax.security.auth.login.password", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ super.loginOk = true;
+
+ return true;
+ }
+
+ protected Principal getIdentity() {
+ return principal;
+ }
+
+ protected Group[] getRoleSets() throws LoginException {
+ return new Group[] {};
+ }
+}
Property changes on: trunk/jboss-integration/src/main/java/org/teiid/jboss/AssosiateCallerIdentityLoginModule.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Modified: trunk/jboss-integration/src/main/java/org/teiid/jboss/deployers/RuntimeEngineDeployer.java
===================================================================
--- trunk/jboss-integration/src/main/java/org/teiid/jboss/deployers/RuntimeEngineDeployer.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/jboss-integration/src/main/java/org/teiid/jboss/deployers/RuntimeEngineDeployer.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -244,7 +244,9 @@
if (this.odbcSocketConfiguration.getEnabled()) {
this.vdbRepository.odbcEnabled();
- this.odbcSocket = new ODBCSocketListener(this.odbcSocketConfiguration, this.dqpCore.getBufferManager(), offset, getMaxODBCLobSizeAllowed());
+ ODBCSocketListener odbc = new ODBCSocketListener(this.odbcSocketConfiguration, this.dqpCore.getBufferManager(), offset, getMaxODBCLobSizeAllowed(), this.logon);
+ odbc.setAuthenticationType(sessionService.getAuthType());
+ this.odbcSocket = odbc;
LogManager.logInfo(LogConstants.CTX_RUNTIME, IntegrationPlugin.Util.getString("odbc_enabled","Teiid ODBC - SSL=", (this.odbcSocketConfiguration.getSSLConfiguration().isSslEnabled()?"ON":"OFF")+" Host = "+this.odbcSocketConfiguration.getHostAddress().getHostName()+" Port = "+(this.odbcSocketConfiguration.getPortNumber()+offset))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
} else {
LogManager.logInfo(LogConstants.CTX_RUNTIME, IntegrationPlugin.Util.getString("odbc_not_enabled")); //$NON-NLS-1$
Modified: trunk/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/main/java/org/teiid/odbc/ODBCClientRemote.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -39,6 +39,12 @@
// AuthenticationCleartextPassword (B)
void useClearTextAuthentication();
+ // AuthenticationGSS (B)
+ void useAuthenticationGSS();
+
+ // AuthenticationGSSContinue (B)
+ void authenticationGSSContinue(byte[] serviceToken);
+
// AuthenticationOk (B)
// BackendKeyData (B)
// ParameterStatus (B)
@@ -101,9 +107,7 @@
// AuthenticationKerberosV5 (B)
// AuthenticationMD5Password (B)
// AuthenticationSCMCredential (B)
- // AuthenticationGSS (B)
// AuthenticationSSPI (B)
- // AuthenticationGSSContinue (B)
// CloseComplete (B)
Modified: trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemote.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemote.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemote.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -23,12 +23,13 @@
import java.util.Properties;
+import org.teiid.transport.PgFrontendProtocol.NullTerminatedStringDataInputStream;
+
public interface ODBCServerRemote {
- enum AuthenticationType {CLEARTEXT, MD5};
void initialize(Properties props);
- void logon(String databaseName, String userid, String password);
+ void logon(String databaseName, String userid, NullTerminatedStringDataInputStream data);
void prepare(String prepareName, String sql, int[] paramType);
Modified: trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -40,6 +40,9 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.teiid.client.security.ILogon;
+import org.teiid.client.security.LogonException;
+import org.teiid.client.security.LogonResult;
import org.teiid.client.util.ResultsFuture;
import org.teiid.core.util.ApplicationInfo;
import org.teiid.core.util.StringUtil;
@@ -50,9 +53,11 @@
import org.teiid.jdbc.TeiidDriver;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
+import org.teiid.net.TeiidURL.CONNECTION.AuthenticationType;
import org.teiid.odbc.PGUtil.PgColInfo;
import org.teiid.runtime.RuntimePlugin;
import org.teiid.transport.ODBCClientInstance;
+import org.teiid.transport.PgFrontendProtocol.NullTerminatedStringDataInputStream;
/**
* While executing the multiple prepared statements I see this bug currently
@@ -165,11 +170,13 @@
private Map<String, Prepared> preparedMap = Collections.synchronizedMap(new HashMap<String, Prepared>());
private Map<String, Portal> portalMap = Collections.synchronizedMap(new HashMap<String, Portal>());
private Map<String, Cursor> cursorMap = Collections.synchronizedMap(new HashMap<String, Cursor>());
+ private ILogon logon;
- public ODBCServerRemoteImpl(ODBCClientInstance client, AuthenticationType authType, TeiidDriver driver) {
+ public ODBCServerRemoteImpl(ODBCClientInstance client, AuthenticationType authType, TeiidDriver driver, ILogon logon) {
this.driver = driver;
this.client = client.getClient();
this.authType = authType;
+ this.logon = logon;
}
@Override
@@ -181,18 +188,39 @@
if (this.authType.equals(AuthenticationType.CLEARTEXT)) {
this.client.useClearTextAuthentication();
}
- else if (this.authType.equals(AuthenticationType.MD5)) {
- // TODO: implement MD5 auth type
+ else if (this.authType.equals(AuthenticationType.KRB5)) {
+ this.client.useAuthenticationGSS();
}
}
@Override
- public void logon(String databaseName, String user, String password) {
+ public void logon(String databaseName, String user, NullTerminatedStringDataInputStream data) {
try {
- java.util.Properties info = new java.util.Properties();
- String url = "jdbc:teiid:"+databaseName+";ApplicationName=ODBC"; //$NON-NLS-1$ //$NON-NLS-2$
+ java.util.Properties info = new java.util.Properties();
info.put("user", user); //$NON-NLS-1$
- info.put("password", password); //$NON-NLS-1$
+
+ String password = null;
+ String passthroughAuthentication = ""; //$NON-NLS-1$
+ if (authType.equals(AuthenticationType.CLEARTEXT)) {
+ password = data.readString();
+ }
+ else if (authType.equals(AuthenticationType.KRB5)) {
+ byte[] serviceToken = data.readServiceToken();
+ LogonResult result = this.logon.neogitiateGssLogin(this.props, serviceToken, false);
+ if ((Boolean)result.getProperty(ILogon.KRB5_ESTABLISHED)) {
+ serviceToken = (byte[])result.getProperty(ILogon.KRB5TOKEN);
+ this.client.authenticationGSSContinue(serviceToken);
+ return;
+ }
+ passthroughAuthentication = ";PassthroughAuthentication=true"; //$NON-NLS-1$
+ }
+
+ String url = "jdbc:teiid:"+databaseName+";ApplicationName=ODBC"+passthroughAuthentication; //$NON-NLS-1$ //$NON-NLS-2$
+
+ if (password != null) {
+ info.put("password", password); //$NON-NLS-1$
+ }
+
this.connection = (ConnectionImpl)driver.connect(url, info);
int hash = this.connection.getConnectionId().hashCode();
Enumeration keys = this.props.propertyNames();
@@ -207,7 +235,13 @@
} catch (SQLException e) {
errorOccurred(e);
terminate();
- }
+ } catch(LogonException e) {
+ errorOccurred(e);
+ terminate();
+ } catch (IOException e) {
+ errorOccurred(e);
+ terminate();
+ }
}
private void cursorExecute(final String cursorName, final String sql, final ResultsFuture<Integer> completion) {
Modified: trunk/runtime/src/main/java/org/teiid/services/SessionServiceImpl.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/services/SessionServiceImpl.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/main/java/org/teiid/services/SessionServiceImpl.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -22,6 +22,8 @@
package org.teiid.services;
+import java.io.IOException;
+import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -33,6 +35,12 @@
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
@@ -55,6 +63,7 @@
import org.teiid.logging.LogManager;
import org.teiid.net.ServerConnection;
import org.teiid.net.TeiidURL;
+import org.teiid.net.TeiidURL.CONNECTION.AuthenticationType;
import org.teiid.runtime.RuntimePlugin;
import org.teiid.security.Credentials;
import org.teiid.security.SecurityHelper;
@@ -72,6 +81,8 @@
*/
private long sessionMaxLimit = DEFAULT_MAX_SESSIONS;
private long sessionExpirationTimeLimit = DEFAULT_SESSION_EXPIRATION;
+ private String authenticationType = AuthenticationType.CLEARTEXT.name();
+ private String krb5SecurityDomain;
/*
* Injected state
@@ -249,6 +260,31 @@
}
@Override
+ public LoginContext createLoginContext(final String securityDomain, final String user, final String password) throws LoginException{
+ CallbackHandler handler = new CallbackHandler() {
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ for (int i = 0; i < callbacks.length; i++) {
+ if (callbacks[i] instanceof NameCallback) {
+ NameCallback nc = (NameCallback)callbacks[i];
+ nc.setName(user);
+ } else if (callbacks[i] instanceof PasswordCallback) {
+ PasswordCallback pc = (PasswordCallback)callbacks[i];
+ if (password != null) {
+ pc.setPassword(password.toCharArray());
+ }
+ } else {
+ throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback"); //$NON-NLS-1$
+ }
+ }
+ }
+ };
+
+ TeiidLoginContext context = new TeiidLoginContext(this.securityHelper);
+ return context.createLoginContext(securityDomain, handler);
+ }
+
+ @Override
public Collection<SessionMetadata> getActiveSessions() throws SessionServiceException {
return new ArrayList<SessionMetadata>(this.sessionCache.values());
}
@@ -333,8 +369,18 @@
public void setSessionExpirationTimeLimit(long limit) {
this.sessionExpirationTimeLimit = limit;
- }
+ }
+ @Override
+ public AuthenticationType getAuthType() {
+ return AuthenticationType.valueOf(this.authenticationType);
+ }
+
+ public void setAuthenticationType(String flag) {
+ this.authenticationType = flag;
+ LogManager.logInfo(LogConstants.CTX_SECURITY, "Authentication Type set to: "+flag); //$NON-NLS-1$
+ }
+
public void setSecurityDomains(String domainNameOrder) {
if (domainNameOrder != null && domainNameOrder.trim().length()>0) {
LogManager.logInfo(LogConstants.CTX_SECURITY, "Security Enabled: true"); //$NON-NLS-1$
@@ -345,7 +391,7 @@
}
}
}
-
+
public void setAdminSecurityDomain(String domain) {
this.adminSecurityDomains.add(domain);
LogManager.logInfo(LogConstants.CTX_SECURITY, "Admin Security Enabled: true"); //$NON-NLS-1$
@@ -376,4 +422,23 @@
public void setDqp(DQPCore dqp) {
this.dqp = dqp;
}
+
+ @Override
+ public void assosiateSubjectInContext(String securityDomain, Subject subject) {
+ Principal principal = null;
+ for(Principal p:subject.getPrincipals()) {
+ principal = p;
+ break;
+ }
+ this.securityHelper.assosiateSecurityContext(securityDomain, this.securityHelper.createSecurityContext(securityDomain, principal, null, subject));
+ }
+
+ public void setKrb5SecurityDomain(String domain) {
+ this.krb5SecurityDomain = domain;
+ }
+
+ @Override
+ public String getKrb5SecurityDomain(){
+ return this.krb5SecurityDomain;
+ }
}
Modified: trunk/runtime/src/main/java/org/teiid/services/TeiidLoginContext.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/services/TeiidLoginContext.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/main/java/org/teiid/services/TeiidLoginContext.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -137,7 +137,7 @@
return null;
}
- protected LoginContext createLoginContext(String domain, CallbackHandler handler) throws LoginException {
+ public LoginContext createLoginContext(String domain, CallbackHandler handler) throws LoginException {
return new LoginContext(domain, handler);
}
Modified: trunk/runtime/src/main/java/org/teiid/transport/LogonImpl.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/transport/LogonImpl.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/main/java/org/teiid/transport/LogonImpl.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -22,11 +22,18 @@
package org.teiid.transport;
+import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Properties;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
import org.teiid.adminapi.impl.SessionMetadata;
import org.teiid.client.security.ILogon;
import org.teiid.client.security.InvalidSessionException;
@@ -34,7 +41,6 @@
import org.teiid.client.security.LogonResult;
import org.teiid.client.security.SessionToken;
import org.teiid.client.util.ResultsFuture;
-import org.teiid.core.ComponentNotFoundException;
import org.teiid.core.CoreConstants;
import org.teiid.core.TeiidComponentException;
import org.teiid.dqp.internal.process.DQPWorkContext;
@@ -44,6 +50,8 @@
import org.teiid.logging.LogManager;
import org.teiid.net.CommunicationException;
import org.teiid.net.TeiidURL;
+import org.teiid.net.TeiidURL.CONNECTION.AuthenticationType;
+import org.teiid.runtime.RuntimePlugin;
import org.teiid.security.Credentials;
@@ -57,8 +65,15 @@
this.clusterName = clusterName;
}
- public LogonResult logon(Properties connProps) throws LogonException,
- ComponentNotFoundException {
+ public LogonResult logon(Properties connProps) throws LogonException, TeiidComponentException, CommunicationException {
+ if (!AuthenticationType.CLEARTEXT.equals(service.getAuthType())) {
+ throw new LogonException(RuntimePlugin.Util.getString("wrong_logon_type_jaas")); //$NON-NLS-1$
+ }
+ return logon(connProps, null);
+ }
+
+
+ private LogonResult logon(Properties connProps, byte[] krb5ServiceTicket) throws LogonException {
DQPWorkContext workContext = DQPWorkContext.getWorkContext();
String oldSessionId = workContext.getSessionId();
String applicationName = connProps.getProperty(TeiidURL.CONNECTION.APP_NAME);
@@ -84,14 +99,88 @@
} catch (InvalidSessionException e) {
}
}
- return new LogonResult(sessionInfo.getSessionToken(), sessionInfo.getVDBName(), sessionInfo.getVDBVersion(), clusterName);
+ LogonResult result = new LogonResult(sessionInfo.getSessionToken(), sessionInfo.getVDBName(), sessionInfo.getVDBVersion(), clusterName);
+ if (krb5ServiceTicket != null) {
+ result.addProperty(ILogon.KRB5TOKEN, krb5ServiceTicket);
+ }
+ return result;
} catch (LoginException e) {
throw new LogonException(e.getMessage());
} catch (SessionServiceException e) {
throw new LogonException(e, e.getMessage());
}
}
-
+
+ class GssAction implements PrivilegedAction<GSSResult> {
+ byte[] serviceTicket;
+
+ public GssAction(byte[] ticket) {
+ this.serviceTicket = ticket;
+ }
+
+ @Override
+ public GSSResult run() {
+ GSSContext context = null;
+ try {
+ GSSManager manager = GSSManager.getInstance();
+ context = manager.createContext((GSSCredential)null);
+ this.serviceTicket = context.acceptSecContext(this.serviceTicket, 0, this.serviceTicket.length);
+ return new GSSResult(context, serviceTicket);
+ } catch (GSSException e) {
+ LogManager.logError(LogConstants.CTX_SECURITY, e, "Kerberos context login failed"); //$NON-NLS-1$
+ }
+ return null;
+ }
+ }
+
+ class GSSResult {
+ GSSContext context;
+ byte[] serviceTicket;
+ public GSSResult(GSSContext context, byte[] serviceTicket) {
+ this.context = context;
+ this.serviceTicket = serviceTicket;
+ }
+ }
+
+ @Override
+ public LogonResult neogitiateGssLogin(Properties connProps, byte[] serviceTicket, boolean createSession) throws LogonException {
+
+ if (!AuthenticationType.KRB5.equals(service.getAuthType())) {
+ throw new LogonException(RuntimePlugin.Util.getString("wrong_logon_type_krb5")); //$NON-NLS-1$
+ }
+
+ String user = connProps.getProperty(TeiidURL.CONNECTION.USER_NAME);
+ String password = connProps.getProperty(TeiidURL.CONNECTION.PASSWORD);
+
+ try {
+ String securityDomain = service.getKrb5SecurityDomain();
+ if (securityDomain == null) {
+ throw new LogonException(RuntimePlugin.Util.getString("no_security_domains")); //$NON-NLS-1$
+ }
+ // If this KRB5 and using keytab, user and password callback handler never gets called
+ LoginContext ctx = service.createLoginContext(securityDomain, user, password);
+ ctx.login();
+ Subject subject = ctx.getSubject();
+ GSSResult result = Subject.doAs(subject, new GssAction(serviceTicket));
+ if (result == null) {
+ throw new LogonException(RuntimePlugin.Util.getString("krb5_login_failed")); //$NON-NLS-1$
+ }
+ if (!result.context.isEstablished() || !createSession) {
+ LogonResult logonResult = new LogonResult(new SessionToken(0, "temp"), "internal", 0, "internal"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ logonResult.addProperty(ILogon.KRB5TOKEN, result.serviceTicket);
+ logonResult.addProperty(ILogon.KRB5_ESTABLISHED, new Boolean(result.context.isEstablished()));
+ return logonResult;
+ }
+
+ LogManager.logDetail(LogConstants.CTX_SECURITY, "Kerberos context established"); //$NON-NLS-1$
+ //connProps.setProperty(TeiidURL.CONNECTION.PASSTHROUGH_AUTHENTICATION, "true"); //$NON-NLS-1$
+ service.assosiateSubjectInContext(securityDomain, subject);
+ return logon(connProps, result.serviceTicket);
+ } catch (LoginException e) {
+ throw new LogonException(e, RuntimePlugin.Util.getString("krb5_login_failed")); //$NON-NLS-1$
+ }
+ }
+
private String updateDQPContext(SessionMetadata s) {
String sessionID = s.getSessionId();
Modified: trunk/runtime/src/main/java/org/teiid/transport/ODBCClientInstance.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/transport/ODBCClientInstance.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/main/java/org/teiid/transport/ODBCClientInstance.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -28,12 +28,14 @@
import java.util.Arrays;
import java.util.concurrent.ConcurrentLinkedQueue;
+import org.teiid.client.security.ILogon;
import org.teiid.core.util.ReflectionHelper;
import org.teiid.jdbc.TeiidDriver;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.logging.MessageLevel;
import org.teiid.net.CommunicationException;
+import org.teiid.net.TeiidURL.CONNECTION.AuthenticationType;
import org.teiid.net.socket.ObjectChannel;
import org.teiid.net.socket.ServiceInvocationStruct;
import org.teiid.odbc.ODBCClientRemote;
@@ -48,7 +50,7 @@
private ReflectionHelper serverProxy = new ReflectionHelper(ODBCServerRemote.class);
private ConcurrentLinkedQueue<PGRequest> messageQueue = new ConcurrentLinkedQueue<PGRequest>();
- public ODBCClientInstance(final ObjectChannel channel, ODBCServerRemote.AuthenticationType authType, TeiidDriver driver) {
+ public ODBCClientInstance(final ObjectChannel channel, AuthenticationType authType, TeiidDriver driver, ILogon logonService) {
this.client = (ODBCClientRemote)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {ODBCClientRemote.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
@@ -60,7 +62,7 @@
return null;
}
});
- this.server = new ODBCServerRemoteImpl(this, authType, driver) {
+ this.server = new ODBCServerRemoteImpl(this, authType, driver, logonService) {
@Override
protected synchronized void doneExecuting() {
super.doneExecuting();
Modified: trunk/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/main/java/org/teiid/transport/ODBCSocketListener.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -25,20 +25,22 @@
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.DefaultChannelPipeline;
+import org.teiid.client.security.ILogon;
import org.teiid.common.buffer.StorageManager;
import org.teiid.core.TeiidException;
import org.teiid.jdbc.EmbeddedProfile;
import org.teiid.jdbc.TeiidDriver;
import org.teiid.net.ServerConnection;
+import org.teiid.net.TeiidURL.CONNECTION.AuthenticationType;
import org.teiid.net.socket.ObjectChannel;
-import org.teiid.odbc.ODBCServerRemote;
public class ODBCSocketListener extends SocketListener {
- private ODBCServerRemote.AuthenticationType authType = ODBCServerRemote.AuthenticationType.CLEARTEXT;
+ private AuthenticationType authType = AuthenticationType.CLEARTEXT;
private int maxLobSize;
private TeiidDriver driver;
+ private ILogon logonService;
- public ODBCSocketListener(SocketConfiguration config, StorageManager storageManager, int portOffset, int maxLobSize) {
+ public ODBCSocketListener(SocketConfiguration config, StorageManager storageManager, int portOffset, int maxLobSize, ILogon logon) {
//the clientserviceregistry isn't actually used by ODBC
super(config, new ClientServiceRegistryImpl(ClientServiceRegistry.Type.ODBC), storageManager, portOffset);
this.maxLobSize = maxLobSize;
@@ -51,6 +53,7 @@
return new LocalServerConnection(info, false);
}
});
+ this.logonService = logon;
}
public void setDriver(TeiidDriver driver) {
@@ -73,11 +76,11 @@
@Override
public ChannelListener createChannelListener(ObjectChannel channel) {
- return new ODBCClientInstance(channel, this.authType, driver);
+ return new ODBCClientInstance(channel, this.authType, driver, logonService);
}
- public void setAuthenticationType(String value) {
- this.authType = ODBCServerRemote.AuthenticationType.valueOf(value);
+ public void setAuthenticationType(AuthenticationType value) {
+ this.authType = value;
}
}
Modified: trunk/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -254,6 +254,24 @@
}
@Override
+ public void useAuthenticationGSS() {
+ try {
+ sendAuthenticationGSS();
+ } catch (IOException e) {
+ terminate(e);
+ }
+ }
+
+ @Override
+ public void authenticationGSSContinue(byte[] serviceToken) {
+ try {
+ sendAuthenticationGSSContinue(serviceToken);
+ } catch (IOException e) {
+ terminate(e);
+ }
+ }
+
+ @Override
public void authenticationSucess(int processId, int screctKey) {
try {
sendAuthenticationOk();
@@ -749,7 +767,20 @@
writeInt(3);
sendMessage();
}
-
+
+ private void sendAuthenticationGSS() throws IOException {
+ startMessage('R');
+ writeInt(7);
+ sendMessage();
+ }
+
+ private void sendAuthenticationGSSContinue(byte[] serviceToken) throws IOException {
+ startMessage('R');
+ writeInt(8);
+ write(serviceToken);
+ sendMessage();
+ }
+
private void sendAuthenticationOk() throws IOException {
startMessage('R');
writeInt(0);
@@ -918,6 +949,5 @@
default:
return PG_TYPE_UNKNOWN;
}
- }
-
+ }
}
Modified: trunk/runtime/src/main/java/org/teiid/transport/PgFrontendProtocol.java
===================================================================
--- trunk/runtime/src/main/java/org/teiid/transport/PgFrontendProtocol.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/main/java/org/teiid/transport/PgFrontendProtocol.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -131,7 +131,7 @@
byte[] data = createByteArray(this.dataLength - 4);
buffer.readBytes(data);
- createRequestMessage(this.messageType, new NullTerminatedStringDataInputStream(new DataInputStream(new ByteArrayInputStream(data, 0, this.dataLength-4)), this.encoding));
+ createRequestMessage(this.messageType, new NullTerminatedStringDataInputStream(data, new DataInputStream(new ByteArrayInputStream(data, 0, this.dataLength-4)), this.encoding));
this.dataLength = null;
this.messageType = null;
return message;
@@ -223,8 +223,7 @@
}
private Object buildLogin(NullTerminatedStringDataInputStream data) throws IOException{
- String password = data.readString();
- this.odbcProxy.logon(this.databaseName, this.user, password);
+ this.odbcProxy.logon(this.databaseName, this.user, data);
return message;
}
@@ -403,12 +402,14 @@
ServiceInvocationStruct struct;
}
- static class NullTerminatedStringDataInputStream extends DataInputStream{
+ public static class NullTerminatedStringDataInputStream extends DataInputStream{
private Charset encoding;
+ private byte[] rawData;
- public NullTerminatedStringDataInputStream(DataInputStream in, Charset encoding) {
+ public NullTerminatedStringDataInputStream(byte[] rawData, DataInputStream in, Charset encoding) {
super(in);
this.encoding = encoding;
+ this.rawData = rawData;
}
public String readString() throws IOException {
@@ -422,6 +423,10 @@
}
return new String(buff.toByteArray(), this.encoding);
}
+
+ public byte[] readServiceToken() {
+ return this.rawData;
+ }
}
private static void trace(Object... msg) {
Modified: trunk/runtime/src/main/resources/org/teiid/runtime/i18n.properties
===================================================================
--- trunk/runtime/src/main/resources/org/teiid/runtime/i18n.properties 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/main/resources/org/teiid/runtime/i18n.properties 2011-08-15 18:31:49 UTC (rev 3382)
@@ -94,4 +94,8 @@
SSLConfiguration.no_anonymous=The anonymous cipher suite TLS_DH_anon_WITH_AES_128_CBC_SHA is not available. Please change the transport to be non-SSL or use non-anonymous SSL.
execution_failed=Cursor execution failed
-PgBackendProtocol.ssl_error=Could not initialize ODBC SSL. non-SSL connections will still be allowed.
\ No newline at end of file
+PgBackendProtocol.ssl_error=Could not initialize ODBC SSL. non-SSL connections will still be allowed.
+wrong_logon_type_jaas = Wrong logon method is being used. Server is not set up for JAAS based authentication. Correct your client's 'AuthenticationType' property.
+wrong_logon_type_krb5 = Wrong logon method is being used. Server is not set up for Kerberos based authentication. Correct your client's 'AuthenticationType' property.
+krb5_login_failed=Kerberos context login failed
+no_security_domains=No security domain configured for Kerberos authentication. Can not authenticate.
\ No newline at end of file
Modified: trunk/runtime/src/test/java/org/teiid/transport/TestLogonImpl.java
===================================================================
--- trunk/runtime/src/test/java/org/teiid/transport/TestLogonImpl.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/test/java/org/teiid/transport/TestLogonImpl.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -34,12 +34,14 @@
import org.teiid.dqp.internal.process.DQPWorkContext;
import org.teiid.dqp.service.SessionService;
import org.teiid.net.TeiidURL;
+import org.teiid.net.TeiidURL.CONNECTION.AuthenticationType;
public class TestLogonImpl extends TestCase {
public void testLogonResult() throws Exception {
SessionService ssi = Mockito.mock(SessionService.class);
+ Mockito.stub(ssi.getAuthType()).toReturn(AuthenticationType.CLEARTEXT);
DQPWorkContext.setWorkContext(new DQPWorkContext());
String userName = "Fred"; //$NON-NLS-1$
String applicationName = "test"; //$NON-NLS-1$
Modified: trunk/runtime/src/test/java/org/teiid/transport/TestSocketRemoting.java
===================================================================
--- trunk/runtime/src/test/java/org/teiid/transport/TestSocketRemoting.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/runtime/src/test/java/org/teiid/transport/TestSocketRemoting.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -193,6 +193,13 @@
TeiidComponentException {
}
+ @Override
+ public LogonResult neogitiateGssLogin(
+ Properties connectionProperties, byte[] serviceToken, boolean createSession)
+ throws LogonException {
+ return null;
+ }
+
}, "foo"); //$NON-NLS-1$
csr.registerClientService(FakeService.class, new FakeServiceImpl(), "foo"); //$NON-NLS-1$
final FakeClientServerInstance serverInstance = new FakeClientServerInstance(csr);
Modified: trunk/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java
===================================================================
--- trunk/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/test-integration/common/src/test/java/org/teiid/transport/TestODBCSocketTransport.java 2011-08-15 18:31:49 UTC (rev 3382)
@@ -47,7 +47,9 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.mockito.Mockito;
import org.postgresql.Driver;
+import org.teiid.client.security.ILogon;
import org.teiid.common.buffer.BufferManagerFactory;
import org.teiid.core.util.UnitTestUtil;
import org.teiid.jdbc.FakeServer;
@@ -127,7 +129,7 @@
addr = new InetSocketAddress(0);
config.setBindAddress(addr.getHostName());
config.setPortNumber(0);
- odbcTransport = new ODBCSocketListener(config, BufferManagerFactory.getStandaloneBufferManager(), 0, 100000);
+ odbcTransport = new ODBCSocketListener(config, BufferManagerFactory.getStandaloneBufferManager(), 0, 100000, Mockito.mock(ILogon.class));
FakeServer server = new FakeServer();
server.setUseCallingThread(false);
Modified: trunk/test-integration/pom.xml
===================================================================
--- trunk/test-integration/pom.xml 2011-08-15 15:36:27 UTC (rev 3381)
+++ trunk/test-integration/pom.xml 2011-08-15 18:31:49 UTC (rev 3382)
@@ -14,7 +14,7 @@
<properties>
<derby.version>10.2.1.6</derby.version>
<mysql.connector.version>5.1.5</mysql.connector.version>
- <postgresql.version>8.3-603.jdbc3</postgresql.version>
+ <postgresql.version>8.4-702.jdbc4</postgresql.version>
<apache.ant.version>1.7.0</apache.ant.version>
</properties>
14 years, 8 months
teiid SVN: r3381 - branches/7.4.x/build/kits/jboss-container/conf.
by teiid-commits@lists.jboss.org
Author: van.halbert
Date: 2011-08-15 11:36:27 -0400 (Mon, 15 Aug 2011)
New Revision: 3381
Modified:
branches/7.4.x/build/kits/jboss-container/conf/jboss-teiid-log4j.xml
Log:
TEIID-1711 Changed <logger> to use <category> in defining the log4j definitions
Modified: branches/7.4.x/build/kits/jboss-container/conf/jboss-teiid-log4j.xml
===================================================================
--- branches/7.4.x/build/kits/jboss-container/conf/jboss-teiid-log4j.xml 2011-08-12 21:21:02 UTC (rev 3380)
+++ branches/7.4.x/build/kits/jboss-container/conf/jboss-teiid-log4j.xml 2011-08-15 15:36:27 UTC (rev 3381)
@@ -1,3 +1,18 @@
+
+ <!-- un-comment to enable Teiid COMMAND log,
+ NOTE: if there are categories above this appender, this will need to be moved above the categories
+ in order for this appender to work.
+ <appender name="COMMAND" class="org.jboss.logging.appender.RollingFileAppender">
+ <param name="File" value="${jboss.server.log.dir}/teiid-command.log"/>
+ <param name="MaxFileSize" value="1000KB"/>
+ <param name="MaxBackupIndex" value="25"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d %-5p [%c] (%t:%x) %m%n"/>
+ </layout>
+ </appender>
+ -->
+
+
<!--
This file contains log4j.xml snippets that can be used in your main jboss-log4j.xml to control
Teiid logging in more depth. By default all messages will go to the org.teiid category and
@@ -5,14 +20,14 @@
-->
<!-- Teiid root category snippet. Use this to control all of Teiid logging from a single category -->
- <logger name="org.teiid">
- <level value="INFO" />
- </logger>
+ <category name="org.teiid">
+ <priority value="INFO" />
+ </category>
<!-- this is to avoid the "Unable to remove nodes to reduce region size below 1024. Set expiration for nodes in this region" error -->
- <logger name="org.jboss.cache">
- <level value="ERROR" />
- </logger>
+ <category name="org.jboss.cache">
+ <priority value="ERROR" />
+ </category>
<!-- Other categories:
org.teiid.PROCESSOR - Query processing logs. See also org.teiid.PLANNER for query planning logs.
@@ -49,27 +64,17 @@
-->
<!-- un-comment to enable COMMAND log - also needs the COMMAND appender to be uncommented
- <logger name="org.teiid.COMMAND_LOG" additivity="false">
- <level value="DEBUG"/>
+ <category name="org.teiid.COMMAND_LOG" additivity="false">
+ <priority value="DEBUG"/>
<appender-ref ref="COMMAND"/>
- </logger>
+ </category>
-->
<!-- Un-comment to enable AUDIT log - also needs the AUDIT appender to be uncommented.
JBoss already has an AUDIT appender, or you may create your own - see the COMMAND appender below
- <logger name="org.teiid.AUDIT_LOG" additivity="false">
- <level value="DEBUG"/>
+ <category name="org.teiid.AUDIT_LOG" additivity="false">
+ <priority value="DEBUG"/>
<appender-ref ref="AUDIT"/>
- </logger>
+ </category>
-->
-
- <!-- un-comment to enable Teiid COMMAND log
- <appender name="COMMAND" class="org.jboss.logging.appender.RollingFileAppender">
- <param name="File" value="${jboss.server.log.dir}/teiid-command.log"/>
- <param name="MaxFileSize" value="1000KB"/>
- <param name="MaxBackupIndex" value="25"/>
- <layout class="org.apache.log4j.PatternLayout">
- <param name="ConversionPattern" value="%d %-5p [%c] (%t:%x) %m%n"/>
- </layout>
- </appender>
- -->
+
14 years, 8 months
teiid SVN: r3380 - in branches/7.4.x: engine/src/main/java/org/teiid/query/optimizer/relational/rules and 4 other directories.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-08-12 17:21:02 -0400 (Fri, 12 Aug 2011)
New Revision: 3380
Added:
branches/7.4.x/metadata/src/test/resources/TEIIDDES992_VDB.vdb
Modified:
branches/7.4.x/api/src/main/java/org/teiid/metadata/FunctionMethod.java
branches/7.4.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CapabilitiesUtil.java
branches/7.4.x/metadata/src/main/java/org/teiid/metadata/index/IndexMetadataFactory.java
branches/7.4.x/metadata/src/test/java/org/teiid/metadata/index/TestMultipleModelIndexes.java
branches/7.4.x/runtime/src/main/java/org/teiid/deployers/CompositeVDB.java
Log:
TEIID-1709 adding support for reading source procedure metadata as a function
Modified: branches/7.4.x/api/src/main/java/org/teiid/metadata/FunctionMethod.java
===================================================================
--- branches/7.4.x/api/src/main/java/org/teiid/metadata/FunctionMethod.java 2011-08-12 14:35:37 UTC (rev 3379)
+++ branches/7.4.x/api/src/main/java/org/teiid/metadata/FunctionMethod.java 2011-08-12 21:21:02 UTC (rev 3380)
@@ -108,7 +108,7 @@
private Determinism determinism = Determinism.DETERMINISTIC;
@XmlElement(name="inputParameters")
- protected List<FunctionParameter> inParameters = new ArrayList<FunctionParameter>();
+ protected List<FunctionParameter> inParameters = new ArrayList<FunctionParameter>(2);
private FunctionParameter outputParameter;
private Schema parent;
Modified: branches/7.4.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CapabilitiesUtil.java
===================================================================
--- branches/7.4.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CapabilitiesUtil.java 2011-08-12 14:35:37 UTC (rev 3379)
+++ branches/7.4.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CapabilitiesUtil.java 2011-08-12 21:21:02 UTC (rev 3380)
@@ -219,7 +219,7 @@
if (!caps.supportsFunction(function.getFunctionDescriptor().getName())) {
return false;
}
- } else if (!schema.getFullName().equalsIgnoreCase(metadata.getFullName(modelID))) {
+ } else if (!isSameConnector(modelID, schema, metadata, capFinder)) {
return false; //not the right schema
}
Modified: branches/7.4.x/metadata/src/main/java/org/teiid/metadata/index/IndexMetadataFactory.java
===================================================================
--- branches/7.4.x/metadata/src/main/java/org/teiid/metadata/index/IndexMetadataFactory.java 2011-08-12 14:35:37 UTC (rev 3379)
+++ branches/7.4.x/metadata/src/main/java/org/teiid/metadata/index/IndexMetadataFactory.java 2011-08-12 21:21:02 UTC (rev 3380)
@@ -55,6 +55,8 @@
import org.teiid.metadata.ColumnSet;
import org.teiid.metadata.Datatype;
import org.teiid.metadata.ForeignKey;
+import org.teiid.metadata.FunctionMethod;
+import org.teiid.metadata.FunctionParameter;
import org.teiid.metadata.KeyRecord;
import org.teiid.metadata.MetadataStore;
import org.teiid.metadata.Procedure;
@@ -62,6 +64,8 @@
import org.teiid.metadata.Schema;
import org.teiid.metadata.Table;
import org.teiid.metadata.VdbConstants;
+import org.teiid.metadata.FunctionMethod.Determinism;
+import org.teiid.metadata.FunctionMethod.PushDown;
import org.teiid.query.metadata.TransformationMetadata;
import org.teiid.query.metadata.TransformationMetadata.Resource;
@@ -425,6 +429,35 @@
if(transformRecord != null) {
procedureRecord.setQueryPlan(transformRecord.getTransformation());
}
+ } else if (procedureRecord.isFunction()) {
+ boolean deterministic = Boolean.valueOf(procedureRecord.getProperties().get("deterministic")); //$NON-NLS-1$
+ FunctionParameter outputParam = null;
+ List<FunctionParameter> args = new ArrayList<FunctionParameter>(procedureRecord.getParameters().size() - 1);
+ boolean valid = true;
+ for (ProcedureParameter param : procedureRecord.getParameters()) {
+ FunctionParameter fp = new FunctionParameter();
+ fp.setName(param.getName());
+ fp.setDescription(param.getAnnotation());
+ fp.setType(param.getRuntimeType());
+ switch (param.getType()) {
+ case ReturnValue:
+ if (outputParam != null) {
+ valid = false;
+ }
+ outputParam = fp;
+ break;
+ case In:
+ args.add(fp);
+ break;
+ default:
+ valid = false;
+ }
+ }
+ if (valid && outputParam != null) {
+ model.addFunction(new FunctionMethod(procedureRecord.getName(), procedureRecord.getAnnotation(), model.getName(), PushDown.MUST_PUSHDOWN,
+ null, null, args.toArray(new FunctionParameter[args.size()]), outputParam, false, deterministic?Determinism.DETERMINISTIC:Determinism.NONDETERMINISTIC));
+ continue;
+ }
}
model.addProcedure(procedureRecord);
}
Modified: branches/7.4.x/metadata/src/test/java/org/teiid/metadata/index/TestMultipleModelIndexes.java
===================================================================
--- branches/7.4.x/metadata/src/test/java/org/teiid/metadata/index/TestMultipleModelIndexes.java 2011-08-12 14:35:37 UTC (rev 3379)
+++ branches/7.4.x/metadata/src/test/java/org/teiid/metadata/index/TestMultipleModelIndexes.java 2011-08-12 21:21:02 UTC (rev 3380)
@@ -27,9 +27,11 @@
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.Collection;
+import java.util.Map;
import org.junit.Test;
import org.teiid.core.util.UnitTestUtil;
+import org.teiid.metadata.FunctionMethod;
import org.teiid.metadata.Schema;
import org.teiid.metadata.Table;
import org.teiid.query.metadata.TransformationMetadata;
@@ -63,4 +65,13 @@
assertNotNull(schema.getFunctions());
}
+ @Test public void testFunctionMetadata() throws Exception {
+ TransformationMetadata tm = VDBMetadataFactory.getVDBMetadata(UnitTestUtil.getTestDataPath() + "/TEIIDDES992_VDB.vdb");
+ Map<String, FunctionMethod> functions = tm.getMetadataStore().getSchema("TEIIDDES992").getFunctions();
+ assertEquals(1, functions.size());
+ FunctionMethod fm = functions.values().iterator().next();
+ assertEquals("sampleFunction", fm.getName());
+ assertEquals(1, fm.getInputParameters().size());
+ }
+
}
Added: branches/7.4.x/metadata/src/test/resources/TEIIDDES992_VDB.vdb
===================================================================
(Binary files differ)
Property changes on: branches/7.4.x/metadata/src/test/resources/TEIIDDES992_VDB.vdb
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Modified: branches/7.4.x/runtime/src/main/java/org/teiid/deployers/CompositeVDB.java
===================================================================
--- branches/7.4.x/runtime/src/main/java/org/teiid/deployers/CompositeVDB.java 2011-08-12 14:35:37 UTC (rev 3379)
+++ branches/7.4.x/runtime/src/main/java/org/teiid/deployers/CompositeVDB.java 2011-08-12 21:21:02 UTC (rev 3380)
@@ -170,7 +170,6 @@
mergedUDF.addFunctions(this.udf);
}
if (this.stores != null) {
- //schema scoped source functions - this is only a dynamic vdb concept
for(MetadataStore store:this.stores.getStores()) {
for (Schema schema:store.getSchemas().values()) {
Collection<FunctionMethod> funcs = schema.getFunctions().values();
14 years, 8 months
teiid SVN: r3379 - in trunk/engine/src: test/java/org/teiid/query/processor/proc and 1 other directory.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-08-12 10:35:37 -0400 (Fri, 12 Aug 2011)
New Revision: 3379
Modified:
trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java
trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java
Log:
TEIID-1701 ensuring that the txn is properly associated
Modified: trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java 2011-08-11 20:12:07 UTC (rev 3378)
+++ trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java 2011-08-12 14:35:37 UTC (rev 3379)
@@ -140,6 +140,7 @@
private boolean requiresTransaction = true;
private TransactionContext blockContext;
+ private boolean inTxn;
/**
* Resources cannot be held open across the txn boundary. This list is a hack at ensuring the resources are closed.
*/
@@ -218,7 +219,7 @@
beginBatch = 1;
batchRows = null;
lastBatch = false;
-
+ inTxn = false;
//reset program stack
programs.clear();
LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "ProcedurePlan reset"); //$NON-NLS-1$
@@ -276,13 +277,15 @@
@Override
public TupleBatch nextBatch() throws BlockedException,
TeiidComponentException, TeiidProcessingException {
- if (blockContext != null) {
+ if (blockContext != null && !this.inTxn) {
this.getContext().getTransactionServer().resume(blockContext);
+ this.inTxn = true;
}
try {
return nextBatchDirect();
} finally {
if (blockContext != null) {
+ this.inTxn = false;
this.getContext().getTransactionServer().suspend(blockContext);
}
}
@@ -602,14 +605,17 @@
TransactionService ts = this.getContext().getTransactionServer();
TransactionContext tc = this.blockContext;
this.blockContext = null;
- for (WeakReference<DataTierTupleSource> ref : txnTupleSources) {
- DataTierTupleSource dtts = ref.get();
- if (dtts != null) {
- dtts.fullyCloseSource();
- }
- }
- this.txnTupleSources.clear();
try {
+ if (!inTxn) {
+ this.getContext().getTransactionServer().resume(tc);
+ }
+ for (WeakReference<DataTierTupleSource> ref : txnTupleSources) {
+ DataTierTupleSource dtts = ref.get();
+ if (dtts != null) {
+ dtts.fullyCloseSource();
+ }
+ }
+ this.txnTupleSources.clear();
if (success) {
ts.commit(tc);
} else {
@@ -636,6 +642,7 @@
if (tc != null && tc.getTransactionType() == Scope.NONE) {
//start a transaction
this.getContext().getTransactionServer().begin(tc);
+ this.inTxn = true;
this.blockContext = tc;
this.peek().setStartedTxn(true);
}
Modified: trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java 2011-08-11 20:12:07 UTC (rev 3378)
+++ trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java 2011-08-12 14:35:37 UTC (rev 3379)
@@ -2523,6 +2523,7 @@
}
Mockito.verify(ts).begin(tc);
+ Mockito.verify(ts).resume(tc);
Mockito.verify(ts, Mockito.times(0)).commit(tc);
Mockito.verify(ts).rollback(tc);
}
14 years, 8 months
teiid SVN: r3378 - in trunk/engine/src/main/java/org/teiid/query/sql: visitor and 1 other directory.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-08-11 16:12:07 -0400 (Thu, 11 Aug 2011)
New Revision: 3378
Modified:
trunk/engine/src/main/java/org/teiid/query/sql/lang/TextTable.java
trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
Log:
TEIID-1703 adding more flexibility to fixed width parsing
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/TextTable.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/TextTable.java 2011-08-11 18:49:54 UTC (rev 3377)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/TextTable.java 2011-08-11 20:12:07 UTC (rev 3378)
@@ -94,7 +94,7 @@
private boolean escape;
private Integer header;
private Integer skip;
- private boolean usingRowDelimiter;
+ private boolean usingRowDelimiter = true;
private boolean fixedWidth;
Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java 2011-08-11 18:49:54 UTC (rev 3377)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java 2011-08-11 20:12:07 UTC (rev 3378)
@@ -1277,7 +1277,11 @@
append(" "); //$NON-NLS-1$
}
- append(((Constant)args[1]).getValue());
+ if (args.length < 2 || args[1] == null || !(args[1] instanceof Constant)) {
+ append(UNDEFINED);
+ } else {
+ append(((Constant)args[1]).getValue());
+ }
}
append(")"); //$NON-NLS-1$
14 years, 8 months
teiid SVN: r3377 - in trunk: documentation/reference/src/main/docbook/en-US/content and 10 other directories.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-08-11 14:49:54 -0400 (Thu, 11 Aug 2011)
New Revision: 3377
Modified:
trunk/build/kits/jboss-container/teiid-releasenotes.html
trunk/documentation/reference/src/main/docbook/en-US/content/grammar.xml
trunk/documentation/reference/src/main/docbook/en-US/content/sql_clauses.xml
trunk/engine/src/main/java/org/teiid/query/processor/relational/TextTableNode.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/TextTable.java
trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
trunk/engine/src/main/resources/org/teiid/query/i18n.properties
trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
trunk/engine/src/test/java/org/teiid/query/processor/TestTextTable.java
trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java
trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
Log:
TEIID-1703 adding more flexibility to fixed width parsing
Modified: trunk/build/kits/jboss-container/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-container/teiid-releasenotes.html 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/build/kits/jboss-container/teiid-releasenotes.html 2011-08-11 18:49:54 UTC (rev 3377)
@@ -28,6 +28,7 @@
<UL>
<LI><B>Procedure language features</B> - Added support for compound/block statements, BEGIN [[NOT] ATOMIC], loop/block labels, and the leave statement. See the reference for more.
<LI><B>File Enhancements</B> - the file translator can now optionally (via the ExceptionIfFileNotFound property) throw an exception if the path refers to a file that doesn't exist. The file resource adapter can be configured to map file names and can prevent parent path .. references. See the Admin Guide or the file-ds.xml template for more.
+ <LI><B>TEXTTABLE Enhancements</B> - TEXTTABLE can now parse fixed width files that do not use a row delimiter and can optionally produce fixed values that haven't been trimmed.
</UL>
<h2><a name="Compatibility">Compatibility Issues</a></h2>
Modified: trunk/documentation/reference/src/main/docbook/en-US/content/grammar.xml
===================================================================
--- trunk/documentation/reference/src/main/docbook/en-US/content/grammar.xml 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/documentation/reference/src/main/docbook/en-US/content/grammar.xml 2011-08-11 18:49:54 UTC (rev 3377)
@@ -664,11 +664,11 @@
<row>
<entry align="right" valign="top"><para><anchor id="prod76" xreflabel="textTable"/>textTable</para></entry>
<entry align="left" valign="top"><para>::=
-<ID> <LPAREN> <link linkend="prod24">expression</link> <link linkend="prod11">nonReserved</link> <link linkend="prod82">textColumn</link> ( <COMMA> <link linkend="prod82">textColumn</link> )* ( <ID> <link linkend="prod68">charVal</link> )? ( ( <ESCAPE> <link linkend="prod68">charVal</link> ) | ( <ID> <link linkend="prod68">charVal</link> ) )? ( <ID> ( <link linkend="prod83">intVal</link> )? )? ( <ID> <link linkend="prod83">intVal</link> )? <RPAREN> ( <AS> )? <link linkend="prod2">id</link></para></entry></row>
+<ID> <LPAREN> <link linkend="prod24">expression</link> <link linkend="prod11">nonReserved</link> <link linkend="prod82">textColumn</link> ( <COMMA> <link linkend="prod82">textColumn</link> )* ( <NO> <ROW> <link linkend="prod11">nonReserved</link> )? ( <ID> <link linkend="prod68">charVal</link> )? ( ( <ESCAPE> <link linkend="prod68">charVal</link> ) | ( <ID> <link linkend="prod68">charVal</link> ) )? ( <ID> ( <link linkend="prod83">intVal</link> )? )? ( <ID> <link linkend="prod83">intVal</link> )? <RPAREN> ( <AS> )? <link linkend="prod2">id</link></para></entry></row>
<row>
<entry align="right" valign="top"><para><anchor id="prod82" xreflabel="textColumn"/>textColumn</para></entry>
<entry align="left" valign="top"><para>::=
-<link linkend="prod2">id</link> <link linkend="prod37">dataType</link> ( <ID> <link linkend="prod83">intVal</link> )?</para></entry></row>
+<link linkend="prod2">id</link> <link linkend="prod37">dataType</link> ( <ID> <link linkend="prod83">intVal</link> ( <NO> <link linkend="prod11">nonReserved</link> )? )?</para></entry></row>
<row>
<entry align="right" valign="top"><para><anchor id="prod84" xreflabel="xmlQuery"/>xmlQuery</para></entry>
<entry align="left" valign="top"><para>::=
Modified: trunk/documentation/reference/src/main/docbook/en-US/content/sql_clauses.xml
===================================================================
--- trunk/documentation/reference/src/main/docbook/en-US/content/sql_clauses.xml 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/documentation/reference/src/main/docbook/en-US/content/sql_clauses.xml 2011-08-11 18:49:54 UTC (rev 3377)
@@ -98,8 +98,8 @@
</para>
<para>
Usage:
- <synopsis label="Usage">TEXTTABLE(expression COLUMNS <COLUMN>, ... [DELIMITER char] [(QUOTE|ESCAPE) char] [HEADER [integer]] [SKIP integer]) AS name</synopsis>
- <synopsis label="Usage">COLUMN := name datatype [WIDTH integer]</synopsis>
+ <synopsis label="Usage">TEXTTABLE(expression COLUMNS <COLUMN>, ... [NO ROW DELIMITER] [DELIMITER char] [(QUOTE|ESCAPE) char] [HEADER [integer]] [SKIP integer]) AS name</synopsis>
+ <synopsis label="Usage">COLUMN := name datatype [WIDTH integer [NO TRIM]]</synopsis>
</para>
<itemizedlist>
<para>Parameters</para>
@@ -108,6 +108,10 @@
</para>
</listitem>
<listitem>
+ <para>NO ROW DELIMITER indicates that fixed parsing should not assume the presense of newline row delimiters.
+ </para>
+ </listitem>
+ <listitem>
<para>DELIMITER sets the field delimiter character to use. Defaults to ','.
</para>
</listitem>
@@ -131,12 +135,20 @@
<para>SKIP specifies the number of text lines (counting every new line) to skip before parsing the contents. HEADER may still be specified with SKP.
</para>
</listitem>
+ <listitem>
+ <para>WIDTH indicates the fixed-width length of a column in characters - not bytes. The CR NL newline value counts as a single character.
+ </para>
+ </listitem>
+ <listitem>
+ <para>NO TRIM specifies that the text value should not be trimmed of all leading and trailing white space.
+ </para>
+ </listitem>
</itemizedlist>
<itemizedlist>
<para>Syntax Rules:
</para>
<listitem>
- <para>If width is specified for one column it must be specified for all columns.
+ <para>If width is specified for one column it must be specified for all columns and be a non-negative integer.
</para>
</listitem>
<listitem>
@@ -144,6 +156,10 @@
</para>
</listitem>
<listitem>
+ <para>If width is not specified, then NO ROW DELIMITER cannot be used.
+ </para>
+ </listitem>
+ <listitem>
<para>The columns names must be not contain duplicates.
</para>
</listitem>
@@ -151,21 +167,25 @@
<itemizedlist>
<para>Examples</para>
<listitem>
- <para>Use of the HEADER parameter, returns 1 row ['b']: <programlisting>select * from texttable('col1,col2,col3\na,b,c' COLUMNS col2 string HEADER) x</programlisting>
+ <para>Use of the HEADER parameter, returns 1 row ['b']: <programlisting>SELECT * FROM TEXTTABLE(UNESCAPE('col1,col2,col3\na,b,c') COLUMNS col2 string HEADER) x</programlisting>
</para>
</listitem>
<listitem>
- <para>Use of fixed width, returns 1 row ['a', 'b', 'c']: <programlisting>select * from texttable('abc' COLUMNS col1 string width 1, col2 string width 1, col3 string width 1) x</programlisting>
+ <para>Use of fixed width, returns 2 rows ['a', 'b', 'c'], ['d', 'e', 'f']: <programlisting>SELECT * FROM TEXTTABLE(UNESCAPE('abc\ndef') COLUMNS col1 string width 1, col2 string width 1, col3 string width 1) x</programlisting>
</para>
</listitem>
<listitem>
- <para>Use of ESCAPE parameter, returns 1 row ['a,', 'b']: <programlisting>select * from texttable('a:,,b' COLUMNS col1 string, col2 string ESCAPE ':') x</programlisting>
+ <para>Use of fixed width without a row delimiter, returns 3 rows ['a'], ['b'], ['c']: <programlisting>SELECT * FROM TEXTTABLE('abc' COLUMNS col1 string width 1 NO ROW DELIMITER) x</programlisting>
</para>
</listitem>
<listitem>
- <para>As a nested table: <programlisting>select x.* from t, texttable(t.clobcolumn COLUMNS first string, second date SKIP 1) x</programlisting>
+ <para>Use of ESCAPE parameter, returns 1 row ['a,', 'b']: <programlisting>SELECT * FROM TEXTTABLE('a:,,b' COLUMNS col1 string, col2 string ESCAPE ':') x</programlisting>
</para>
</listitem>
+ <listitem>
+ <para>As a nested table: <programlisting>SELECT x.* FROM t, TEXTTABLE(t.clobcolumn COLUMNS first string, second date SKIP 1) x</programlisting>
+ </para>
+ </listitem>
</itemizedlist>
</section>
<section id="xmltable">
Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/TextTableNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/TextTableNode.java 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/TextTableNode.java 2011-08-11 18:49:54 UTC (rev 3377)
@@ -51,9 +51,6 @@
/**
* Handles text file processing.
*
- * TODO: unix style escape handling \t \n, etc. - see also the unescape function
- * TODO: allow for escaping with fixed parsing
- * TODO: allow for fixed parsing without new lines
* TODO: allow for a configurable line terminator
*/
public class TextTableNode extends SubqueryAwareRelationalNode {
@@ -211,14 +208,21 @@
if (eof) {
return null;
}
- continue; //skip empty lines
+ if (table.isUsingRowDelimiter()) {
+ continue; //skip empty lines
+ }
}
- if (exact && sb.length() < lineWidth) {
- throw new TeiidProcessingException(QueryPlugin.Util.getString("TextTableNode.invalid_width", sb.length(), lineWidth, textLine, systemId)); //$NON-NLS-1$
- }
- return sb.toString();
+ if (table.isUsingRowDelimiter()) {
+ if (exact && sb.length() < lineWidth) {
+ throw new TeiidProcessingException(QueryPlugin.Util.getString("TextTableNode.invalid_width", sb.length(), lineWidth, textLine, systemId)); //$NON-NLS-1$
+ }
+ return sb.toString();
+ }
}
sb.append(c);
+ if (exact && sb.length() == maxLength && !table.isUsingRowDelimiter()) {
+ return sb.toString();
+ }
if (sb.length() > maxLength) {
if (exact) {
sb.deleteCharAt(sb.length() - 1);
@@ -433,7 +437,7 @@
int beginIndex = 0;
for (TextColumn col : table.getColumns()) {
String val = new String(line.substring(beginIndex, beginIndex + col.getWidth()));
- addValue(result, false, val);
+ addValue(result, col.isNoTrim(), val);
beginIndex += col.getWidth();
}
return result;
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/TextTable.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/TextTable.java 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/TextTable.java 2011-08-11 18:49:54 UTC (rev 3377)
@@ -36,10 +36,12 @@
public static class TextColumn extends ProjectedColumn {
private Integer width;
+ private boolean noTrim;
- public TextColumn(String name, String type, Integer width) {
+ public TextColumn(String name, String type, Integer width, boolean noTrim) {
super(name, type);
this.width = width;
+ this.noTrim = noTrim;
}
protected TextColumn() {
@@ -54,6 +56,14 @@
this.width = width;
}
+ public boolean isNoTrim() {
+ return noTrim;
+ }
+
+ public void setNoTrim(boolean noTrim) {
+ this.noTrim = noTrim;
+ }
+
@Override
public boolean equals(Object obj) {
if (obj == this) {
@@ -63,13 +73,15 @@
return false;
}
TextColumn other = (TextColumn)obj;
- return EquivalenceUtil.areEqual(width, other.width);
+ return EquivalenceUtil.areEqual(width, other.width)
+ && noTrim == other.noTrim;
}
@Override
public TextColumn clone() {
TextColumn clone = new TextColumn();
clone.width = this.width;
+ clone.noTrim = this.noTrim;
this.copyTo(clone);
return clone;
}
@@ -82,6 +94,7 @@
private boolean escape;
private Integer header;
private Integer skip;
+ private boolean usingRowDelimiter;
private boolean fixedWidth;
@@ -148,6 +161,14 @@
public void setFile(Expression file) {
this.file = file;
}
+
+ public boolean isUsingRowDelimiter() {
+ return usingRowDelimiter;
+ }
+
+ public void setUsingRowDelimiter(boolean usingRowDelimiter) {
+ this.usingRowDelimiter = usingRowDelimiter;
+ }
@Override
public void acceptVisitor(LanguageVisitor visitor) {
@@ -168,6 +189,7 @@
clone.getColumns().add(column.clone());
}
clone.fixedWidth = this.fixedWidth;
+ clone.usingRowDelimiter = this.usingRowDelimiter;
return clone;
}
@@ -186,7 +208,8 @@
&& EquivalenceUtil.areEqual(escape, other.escape)
&& EquivalenceUtil.areEqual(quote, other.quote)
&& EquivalenceUtil.areEqual(header, other.header)
- && EquivalenceUtil.areEqual(skip, other.skip);
+ && EquivalenceUtil.areEqual(skip, other.skip)
+ && usingRowDelimiter == other.usingRowDelimiter;
}
}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java 2011-08-11 18:49:54 UTC (rev 3377)
@@ -1277,11 +1277,7 @@
append(" "); //$NON-NLS-1$
}
- if (args.length < 2 || args[1] == null || !(args[1] instanceof Constant)) {
- append(UNDEFINED);
- } else {
- append(((Constant)args[1]).getValue());
- }
+ append(((Constant)args[1]).getValue());
}
append(")"); //$NON-NLS-1$
@@ -1811,10 +1807,24 @@
append(SPACE);
append(col.getWidth());
}
+ if (col.isNoTrim()) {
+ append(SPACE);
+ append(NO);
+ append(SPACE);
+ append(NonReserved.TRIM);
+ }
if (cols.hasNext()) {
append(","); //$NON-NLS-1$
}
}
+ if (!obj.isUsingRowDelimiter()) {
+ append(SPACE);
+ append(NO);
+ append(SPACE);
+ append(ROW);
+ append(SPACE);
+ append(NonReserved.DELIMITER);
+ }
if (obj.getDelimiter() != null) {
append(SPACE);
append(NonReserved.DELIMITER);
Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java 2011-08-11 18:49:54 UTC (rev 3377)
@@ -1474,6 +1474,9 @@
if (obj.getHeader() != null && obj.getHeader() < 0) {
handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.text_table_negative"), obj); //$NON-NLS-1$
}
+ if (!obj.isUsingRowDelimiter()) {
+ handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.fixed_option"), obj); //$NON-NLS-1$
+ }
delimiter = obj.getDelimiter();
quote = obj.getQuote();
validateTextOptions(obj, delimiter, quote);
Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj 2011-08-11 18:49:54 UTC (rev 3377)
@@ -2287,6 +2287,7 @@
Expression file = null;
TextTable.TextColumn column = null;
List<TextTable.TextColumn> columns = new ArrayList<TextTable.TextColumn>();
+ boolean useRowDelimiter = true;
Character delimiter = null;
boolean escape = false;
Character quote = null;
@@ -2308,6 +2309,12 @@
}
)*
[
+ <NO> <ROW> nonReserved("DELIMITER")
+ {
+ useRowDelimiter = false;
+ }
+ ]
+ [
LOOKAHEAD(<ID>, { "delimiter".equalsIgnoreCase(getToken(1).image) }) <ID>
delimiter = charVal(info, "DELMITER")
]
@@ -2344,6 +2351,7 @@
result.setSkip(skip);
result.setName(validateAlias(aliasID));
result.setQuote(quote);
+ result.setUsingRowDelimiter(useRowDelimiter);
return result;
}
}
@@ -2353,6 +2361,7 @@
String name = null;
Constant datatype = null;
Integer width = null;
+ boolean noTrim = false;
}
{
name = id()
@@ -2360,9 +2369,15 @@
[
LOOKAHEAD(<ID>, { "width".equalsIgnoreCase(getToken(1).image) }) <ID>
width = intVal()
+ [ LOOKAHEAD(2)
+ <NO> nonReserved("TRIM")
+ {
+ noTrim = true;
+ }
+ ]
]
{
- return new TextTable.TextColumn(validateElementName(name), (String)datatype.getValue(), width);
+ return new TextTable.TextColumn(validateElementName(name), (String)datatype.getValue(), width, noTrim);
}
}
Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2011-08-11 18:49:54 UTC (rev 3377)
@@ -816,7 +816,8 @@
TextTableNode.character_not_allowed=Text parse error: Non-whitespace character found between the qualifier and the delimiter in text line {0} in {1}.
TextTableNode.unknown_escape=Text parse error: Unknown escape sequence \\{0} in text line {1} in {2}.
TextTableNode.invalid_width=Text parse error: Fixed width line width {0} is smaller than the expected {1} on text line {2} in {3}.
-TextTableNode.line_too_long=Text parse error: Delimited line is longer than the expected max of {2} on text line {0} in {1}.
+TextTableNode.line_too_long=Text parse error: Delimited line is longer than the expected max of {2} on text line {0} in {1}.
+ValidationVisitor.fixed_option=NO ROW DELIMITER can only be used in fixed parsing mode.
XMLTableNode.error=Error evaluating XQuery row context for XMLTable: {0}
XMLTableNode.path_error=Error evaluating XMLTable column path expression for column: {0}
Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java 2011-08-11 18:49:54 UTC (rev 3377)
@@ -6710,8 +6710,8 @@
TextTable tt = new TextTable();
tt.setFile(new ElementSymbol("file"));
List<TextTable.TextColumn> columns = new ArrayList<TextTable.TextColumn>();
- columns.add(new TextTable.TextColumn("x", "string", 1));
- columns.add(new TextTable.TextColumn("y", "date", 10));
+ columns.add(new TextTable.TextColumn("x", "string", 1, false));
+ columns.add(new TextTable.TextColumn("y", "date", 10, false));
tt.setColumns(columns);
tt.setSkip(10);
tt.setName("x");
Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestTextTable.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestTextTable.java 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestTextTable.java 2011-08-11 18:49:54 UTC (rev 3377)
@@ -159,6 +159,29 @@
process(sql, expected);
}
+ @Test public void testNoRowDelimiter() throws Exception {
+ String sql = "select * from texttable('abcdef' COLUMNS c1 string width 1, c2 string width 1 no row delimiter) x"; //$NON-NLS-1$
+
+ List[] expected = new List[] {
+ Arrays.asList("a","b"),
+ Arrays.asList("c","d"),
+ Arrays.asList("e","f"),
+ };
+
+ process(sql, expected);
+ }
+
+ @Test public void testNoTrim() throws Exception {
+ String sql = "select * from texttable('a b \nc d' COLUMNS c1 string width 2, c2 string width 2 no trim) x"; //$NON-NLS-1$
+
+ List[] expected = new List[] {
+ Arrays.asList("a","b "),
+ Arrays.asList("c"," d"),
+ };
+
+ process(sql, expected);
+ }
+
@Test public void testNoRows() throws Exception {
String sql = "select * from texttable('' COLUMNS c1 string, c2 string SKIP 3) x"; //$NON-NLS-1$
Modified: trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java 2011-08-11 18:49:54 UTC (rev 3377)
@@ -1901,5 +1901,10 @@
@Test public void testSimilar() throws Exception {
helpTestExpression("x similar to 'b' escape 'c'", "x SIMILAR TO 'b' ESCAPE 'c'");
}
+
+ @Test public void testTextTable() throws Exception {
+ String sql = "SELECT * from texttable(file columns x string WIDTH 1 NO TRIM NO ROW DELIMITER) as x"; //$NON-NLS-1$
+ helpTest(QueryParser.getQueryParser().parseCommand(sql), "SELECT * FROM TEXTTABLE(file COLUMNS x string WIDTH 1 NO TRIM NO ROW DELIMITER) AS x");
+ }
}
Modified: trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java 2011-08-11 15:59:42 UTC (rev 3376)
+++ trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java 2011-08-11 18:49:54 UTC (rev 3377)
@@ -1772,6 +1772,10 @@
helpValidate("SELECT * from texttable(null columns x string width 1 DELIMITER 'z') as x", new String[] {"TEXTTABLE(null COLUMNS x string WIDTH 1 DELIMITER 'z') AS x"}, RealMetadataFactory.exampleBQTCached());
}
+ @Test public void testTextTableNoRowDelimiter() {
+ helpValidate("SELECT * from texttable(null columns x string NO ROW DELIMITER) as x", new String[] {"TEXTTABLE(null COLUMNS x string NO ROW DELIMITER) AS x"}, RealMetadataFactory.exampleBQTCached());
+ }
+
@Test public void testXMLNamespaces() {
helpValidate("select xmlforest(xmlnamespaces(no default, default 'http://foo'), e1 as \"table\") from pm1.g1", new String[] {"XMLNAMESPACES(NO DEFAULT, DEFAULT 'http://foo')"}, RealMetadataFactory.example1Cached());
}
14 years, 8 months
teiid SVN: r3376 - in branches/7.4.x/engine/src: test/java/org/teiid/query/processor and 1 other directory.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-08-11 11:59:42 -0400 (Thu, 11 Aug 2011)
New Revision: 3376
Modified:
branches/7.4.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java
branches/7.4.x/engine/src/test/java/org/teiid/query/processor/TestTextTable.java
Log:
TEIID-1706 fix to join planning with nested tables
Modified: branches/7.4.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java
===================================================================
--- branches/7.4.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java 2011-08-11 11:36:26 UTC (rev 3375)
+++ branches/7.4.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java 2011-08-11 15:59:42 UTC (rev 3376)
@@ -466,7 +466,9 @@
}
JoinType jt = (JoinType)root.getProperty(NodeConstants.Info.JOIN_TYPE);
- boolean treatJoinAsSource = jt.isOuter() || root.getProperty(NodeConstants.Info.ACCESS_PATTERNS) != null || root.hasProperty(NodeConstants.Info.MAKE_DEP) || root.hasProperty(NodeConstants.Info.MAKE_IND);
+ boolean treatJoinAsSource = jt.isOuter() || root.getProperty(NodeConstants.Info.ACCESS_PATTERNS) != null
+ || root.hasProperty(NodeConstants.Info.MAKE_DEP) || root.hasProperty(NodeConstants.Info.MAKE_IND)
+ || !root.getExportedCorrelatedReferences().isEmpty();
if (treatJoinAsSource) {
currentRegion.addJoinSourceNode(root);
Modified: branches/7.4.x/engine/src/test/java/org/teiid/query/processor/TestTextTable.java
===================================================================
--- branches/7.4.x/engine/src/test/java/org/teiid/query/processor/TestTextTable.java 2011-08-11 11:36:26 UTC (rev 3375)
+++ branches/7.4.x/engine/src/test/java/org/teiid/query/processor/TestTextTable.java 2011-08-11 15:59:42 UTC (rev 3376)
@@ -22,6 +22,7 @@
package org.teiid.query.processor;
+import static org.junit.Assert.*;
import static org.teiid.query.optimizer.TestOptimizer.*;
import static org.teiid.query.processor.TestProcessor.*;
@@ -43,6 +44,9 @@
import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
import org.teiid.query.optimizer.capabilities.FakeCapabilitiesFinder;
import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
+import org.teiid.query.processor.relational.JoinNode;
+import org.teiid.query.processor.relational.NestedTableJoinStrategy;
+import org.teiid.query.processor.relational.RelationalPlan;
import org.teiid.query.unittest.RealMetadataFactory;
@SuppressWarnings({"unchecked", "nls"})
@@ -243,8 +247,26 @@
};
process(sql, expected);
- }
+ }
+ @Test public void testTextTableJoin() throws Exception {
+ String sql = "select z.* from (select x.* from (select * from pm1.g1 where e1 = 'c') y, texttable(e1 || '\n' || e2 || '\n' || e3 COLUMNS x string) x) as z, " +
+ "(select x.* from (select * from pm1.g1 where e1 = 'c') y, texttable(e1 || '\n' || e2 || '\n' || e3 COLUMNS x string) x) as z1 where z.x = z1.x";
+
+ List[] expected = new List[] {
+ Arrays.asList("c"),
+ Arrays.asList("1"),
+ Arrays.asList("true"),
+ };
+
+ FakeDataManager dataManager = new FakeDataManager();
+ sampleData1(dataManager);
+ RelationalPlan plan = (RelationalPlan)helpGetPlan(helpParse(sql), RealMetadataFactory.example1Cached());
+ JoinNode join = (JoinNode) plan.getRootNode().getChildren()[0];
+ assertTrue(!(join.getJoinStrategy() instanceof NestedTableJoinStrategy));
+ helpProcess(plan, createCommandContext(), dataManager, expected);
+ }
+
public static void process(String sql, List[] expectedResults) throws Exception {
FakeDataManager dataManager = new FakeDataManager();
sampleData1(dataManager);
14 years, 8 months
teiid SVN: r3375 - in branches/7.4.x/engine/src: test/java/org/teiid/query/processor/relational and 1 other directory.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-08-11 07:36:26 -0400 (Thu, 11 Aug 2011)
New Revision: 3375
Modified:
branches/7.4.x/engine/src/main/java/org/teiid/query/processor/relational/RelationalNodeUtil.java
branches/7.4.x/engine/src/test/java/org/teiid/query/processor/relational/TestAccessNode.java
Log:
TEIID-1704 fix for not returning rows from implicit grouping
Modified: branches/7.4.x/engine/src/main/java/org/teiid/query/processor/relational/RelationalNodeUtil.java
===================================================================
--- branches/7.4.x/engine/src/main/java/org/teiid/query/processor/relational/RelationalNodeUtil.java 2011-08-10 20:39:40 UTC (rev 3374)
+++ branches/7.4.x/engine/src/main/java/org/teiid/query/processor/relational/RelationalNodeUtil.java 2011-08-11 11:36:26 UTC (rev 3375)
@@ -108,6 +108,11 @@
}
return true;
}
+
+ if (query.hasAggregates() && query.getGroupBy() == null) {
+ return true;
+ }
+
break;
case Command.TYPE_INSERT:
Insert insert = (Insert) command;
Modified: branches/7.4.x/engine/src/test/java/org/teiid/query/processor/relational/TestAccessNode.java
===================================================================
--- branches/7.4.x/engine/src/test/java/org/teiid/query/processor/relational/TestAccessNode.java 2011-08-10 20:39:40 UTC (rev 3374)
+++ branches/7.4.x/engine/src/test/java/org/teiid/query/processor/relational/TestAccessNode.java 2011-08-11 11:36:26 UTC (rev 3375)
@@ -124,4 +124,9 @@
Query query = (Query)QueryParser.getQueryParser().parseCommand("SELECT e1, e2 FROM pm1.g1 LIMIT 0"); //$NON-NLS-1$
assertFalse(RelationalNodeUtil.shouldExecute(query, false));
}
+
+ @Test public void testShouldExecuteAgg() throws Exception {
+ Query query = (Query)QueryParser.getQueryParser().parseCommand("SELECT count(*) FROM pm1.g1 where false"); //$NON-NLS-1$
+ assertTrue(RelationalNodeUtil.shouldExecute(query, false));
+ }
}
14 years, 8 months