diff --git a/blackbox/docs/sql/administration/user_management.txt b/blackbox/docs/sql/administration/user_management.txt index 57c868f3f1c9..a57271865eb0 100644 --- a/blackbox/docs/sql/administration/user_management.txt +++ b/blackbox/docs/sql/administration/user_management.txt @@ -102,6 +102,12 @@ To list all existing users query that table:: The column ``name`` shows the unique name of the user, the column ``superuser`` shows whether the user has superuser privileges or not. +.. note:: + + We also support retrieving the current connected user using the system + information functions: :ref:`CURRENT_USER `, + :ref:`USER ` and :ref:`SESSION_USER `. + .. warning:: When the :ref:`es_api_setting` is enabled, it is possible to read the users diff --git a/enterprise/users/src/main/java/io/crate/plugin/UsersPlugin.java b/enterprise/users/src/main/java/io/crate/plugin/UsersPlugin.java index 8b650721e7fd..3f4a5279d8b5 100644 --- a/enterprise/users/src/main/java/io/crate/plugin/UsersPlugin.java +++ b/enterprise/users/src/main/java/io/crate/plugin/UsersPlugin.java @@ -1,42 +1,47 @@ /* - * Licensed to Crate under one or more contributor license agreements. - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. Crate licenses this file - * to you under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. You may - * obtain a copy of the License at + * This file is part of a module with proprietary Enterprise Features. * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed to Crate.io Inc. ("Crate.io") under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. See the License for the specific language governing - * permissions and limitations under the License. + * Unauthorized copying of this file, via any medium is strictly prohibited. * - * However, if you have executed another commercial license agreement - * with Crate these terms will supersede the license and you may use the - * software solely pursuant to the terms of the relevant commercial - * agreement. + * To use this file, Crate.io must have given you permission to enable and + * use such Enterprise Features and you must have a valid Enterprise or + * Subscription Agreement with Crate.io. If you enable or use the Enterprise + * Features, you represent and warrant that you have a valid Enterprise or + * Subscription Agreement with Crate.io. Your use of the Enterprise Features + * if governed by the terms and conditions of your Enterprise or Subscription + * Agreement with Crate.io. */ package io.crate.plugin; import io.crate.metadata.UsersMetaData; import io.crate.metadata.UsersPrivilegesMetaData; +import io.crate.scalar.UsersScalarFunctionModule; +import io.crate.settings.SharedSettings; import org.elasticsearch.cluster.NamedDiff; import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.plugins.Plugin; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; public class UsersPlugin extends Plugin { - public UsersPlugin() { + private final Settings settings; + + public UsersPlugin(Settings settings) { + this.settings = settings; } @Override @@ -81,4 +86,13 @@ public List getNamedXContent() { )); return entries; } + + @Override + public Collection createGuiceModules() { + if (SharedSettings.ENTERPRISE_LICENSE_SETTING.setting().get(settings)) { + return Collections.singletonList(new UsersScalarFunctionModule()); + } else { + return Collections.emptyList(); + } + } } diff --git a/enterprise/users/src/main/java/io/crate/scalar/UsersScalarFunctionModule.java b/enterprise/users/src/main/java/io/crate/scalar/UsersScalarFunctionModule.java new file mode 100644 index 000000000000..0e4029d147c8 --- /dev/null +++ b/enterprise/users/src/main/java/io/crate/scalar/UsersScalarFunctionModule.java @@ -0,0 +1,38 @@ +/* + * This file is part of a module with proprietary Enterprise Features. + * + * Licensed to Crate.io Inc. ("Crate.io") under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * Unauthorized copying of this file, via any medium is strictly prohibited. + * + * To use this file, Crate.io must have given you permission to enable and + * use such Enterprise Features and you must have a valid Enterprise or + * Subscription Agreement with Crate.io. If you enable or use the Enterprise + * Features, you represent and warrant that you have a valid Enterprise or + * Subscription Agreement with Crate.io. Your use of the Enterprise Features + * if governed by the terms and conditions of your Enterprise or Subscription + * Agreement with Crate.io. + */ + +package io.crate.scalar; + +import io.crate.metadata.FunctionIdent; +import io.crate.metadata.FunctionImplementation; +import io.crate.scalar.systeminformation.UserFunction; +import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.inject.multibindings.MapBinder; + +public class UsersScalarFunctionModule extends AbstractModule { + + @Override + protected void configure() { + MapBinder functionBinder = + MapBinder.newMapBinder(binder(), FunctionIdent.class, FunctionImplementation.class); + UserFunction currentUserFunction = new UserFunction(UserFunction.CURRENT_USER_FUNCTION_NAME); + functionBinder.addBinding(currentUserFunction.info().ident()).toInstance(currentUserFunction); + UserFunction sessionUserFunction = new UserFunction(UserFunction.SESSION_USER_FUNCTION_NAME); + functionBinder.addBinding(sessionUserFunction.info().ident()).toInstance(sessionUserFunction); + } +} diff --git a/sql/src/main/java/io/crate/operation/scalar/systeminformation/UserFunction.java b/enterprise/users/src/main/java/io/crate/scalar/systeminformation/UserFunction.java similarity index 70% rename from sql/src/main/java/io/crate/operation/scalar/systeminformation/UserFunction.java rename to enterprise/users/src/main/java/io/crate/scalar/systeminformation/UserFunction.java index 6a3febc5e6b5..6b8519961750 100644 --- a/sql/src/main/java/io/crate/operation/scalar/systeminformation/UserFunction.java +++ b/enterprise/users/src/main/java/io/crate/scalar/systeminformation/UserFunction.java @@ -16,7 +16,7 @@ * Agreement with Crate.io. */ -package io.crate.operation.scalar.systeminformation; +package io.crate.scalar.systeminformation; import com.google.common.collect.ImmutableList; import io.crate.analyze.symbol.Function; @@ -24,38 +24,27 @@ import io.crate.analyze.symbol.Symbol; import io.crate.analyze.symbol.format.FunctionFormatSpec; import io.crate.data.Input; -import io.crate.exceptions.UnsupportedFeatureException; import io.crate.metadata.FunctionIdent; import io.crate.metadata.FunctionInfo; import io.crate.metadata.Scalar; import io.crate.metadata.TransactionContext; -import io.crate.operation.scalar.ScalarFunctionModule; import io.crate.operation.user.User; -import io.crate.settings.SharedSettings; import io.crate.types.DataTypes; import org.apache.lucene.util.BytesRef; -import org.elasticsearch.common.settings.Settings; import javax.annotation.Nullable; import java.util.Locale; public class UserFunction extends Scalar implements FunctionFormatSpec { - static final String CURRENT_USER_FUNCTION_NAME = "current_user"; - static final String SESSION_USER_FUNCTION_NAME = "session_user"; + public static final String CURRENT_USER_FUNCTION_NAME = "current_user"; + public static final String SESSION_USER_FUNCTION_NAME = "session_user"; - public static void register(ScalarFunctionModule scalarFunctionModule, Settings settings) { - scalarFunctionModule.register(new UserFunction(CURRENT_USER_FUNCTION_NAME, settings)); - scalarFunctionModule.register(new UserFunction(SESSION_USER_FUNCTION_NAME, settings)); - } - - public final String name; - private final boolean enterpriseEnabled; - public final FunctionInfo functionInfo; + private final String name; + private final FunctionInfo functionInfo; - public UserFunction(String name, Settings settings) { + public UserFunction(String name) { this.name = name; - this.enterpriseEnabled = SharedSettings.ENTERPRISE_LICENSE_SETTING.setting().get(settings); this.functionInfo = new FunctionInfo(new FunctionIdent(name, ImmutableList.of()), DataTypes.STRING); } @@ -72,11 +61,6 @@ public BytesRef evaluate(Input... args) { @Override public Symbol normalizeSymbol(Function symbol, @Nullable TransactionContext transactionContext) { - if (enterpriseEnabled == false) { - throw new UnsupportedFeatureException( - String.format(Locale.ENGLISH, "%s function is only supported in enterprise version", name) - ); - } if (transactionContext == null) { return Literal.NULL; } diff --git a/enterprise/users/src/test/java/io/crate/scalar/systeminformation/UserFunctionTest.java b/enterprise/users/src/test/java/io/crate/scalar/systeminformation/UserFunctionTest.java new file mode 100644 index 000000000000..08cf4c3085bc --- /dev/null +++ b/enterprise/users/src/test/java/io/crate/scalar/systeminformation/UserFunctionTest.java @@ -0,0 +1,104 @@ +/* + * This file is part of a module with proprietary Enterprise Features. + * + * Licensed to Crate.io Inc. ("Crate.io") under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * Unauthorized copying of this file, via any medium is strictly prohibited. + * + * To use this file, Crate.io must have given you permission to enable and + * use such Enterprise Features and you must have a valid Enterprise or + * Subscription Agreement with Crate.io. If you enable or use the Enterprise + * Features, you represent and warrant that you have a valid Enterprise or + * Subscription Agreement with Crate.io. Your use of the Enterprise Features + * if governed by the terms and conditions of your Enterprise or Subscription + * Agreement with Crate.io. + */ + +package io.crate.scalar.systeminformation; + +import io.crate.action.sql.Option; +import io.crate.action.sql.SessionContext; +import io.crate.analyze.symbol.Symbol; +import io.crate.analyze.symbol.format.SymbolPrinter; +import io.crate.operation.scalar.AbstractScalarFunctionsTest; +import io.crate.operation.user.User; +import io.crate.scalar.UsersScalarFunctionModule; +import io.crate.testing.SqlExpressions; +import org.junit.Test; + +import java.util.Collections; + +import static io.crate.testing.SymbolMatchers.isLiteral; +import static org.hamcrest.Matchers.is; + +public class UserFunctionTest extends AbstractScalarFunctionsTest { + + private static final User TEST_USER = new User("testUser", Collections.emptySet(), Collections.emptySet()); + + private void setupFunctionsForTestUser() { + SessionContext sessionContext = new SessionContext(0, Option.NONE, null, TEST_USER, + s -> {}, t -> {}); + sqlExpressions = new SqlExpressions(tableSources, null, null, sessionContext, + new UsersScalarFunctionModule()); + functions = sqlExpressions.functions(); + } + + @Test + public void testNormalizeCurrentUser() { + setupFunctionsForTestUser(); + assertNormalize("current_user", isLiteral("testUser"), false); + } + + @Test + public void testNormalizeSessionUser() { + setupFunctionsForTestUser(); + assertNormalize("session_user", isLiteral("testUser"), false); + } + + @Test + public void testNormalizeUser() { + setupFunctionsForTestUser(); + assertNormalize("user", isLiteral("testUser"), false); + } + + @Test + public void testCurrentUserForMissingUserReturnsNull() { + setupFunctionsWithoutUser(); + assertNormalize("current_user", isLiteral(null), false); + } + + @Test + public void testUserForMissingUserReturnsNull() { + setupFunctionsWithoutUser(); + assertNormalize("user", isLiteral(null), false); + } + + @Test + public void testSessionUserForMissingUserReturnsNull() { + setupFunctionsWithoutUser(); + assertNormalize("session_user", isLiteral(null), false); + } + + @Test + public void testFormatFunctionsWithoutBrackets() { + setupFunctionsForTestUser(); + SymbolPrinter printer = new SymbolPrinter(sqlExpressions.functions()); + Symbol f = sqlExpressions.asSymbol("current_user"); + assertThat(printer.printFullQualified(f), is("current_user")); + + f = sqlExpressions.asSymbol("session_user"); + assertThat(printer.printFullQualified(f), is("session_user")); + + f = sqlExpressions.asSymbol("user"); + assertThat(printer.printFullQualified(f), is("current_user")); + } + + private void setupFunctionsWithoutUser() { + SessionContext sessionContext = new SessionContext(0, Option.NONE, null, null, null, null); + sqlExpressions = new SqlExpressions(tableSources, null, null, sessionContext, new UsersScalarFunctionModule()); + functions = sqlExpressions.functions(); + } +} + diff --git a/sql/src/main/java/io/crate/operation/scalar/ScalarFunctionModule.java b/sql/src/main/java/io/crate/operation/scalar/ScalarFunctionModule.java index 748a86a06d94..c56d30034948 100644 --- a/sql/src/main/java/io/crate/operation/scalar/ScalarFunctionModule.java +++ b/sql/src/main/java/io/crate/operation/scalar/ScalarFunctionModule.java @@ -43,27 +43,20 @@ import io.crate.operation.scalar.string.LengthFunction; import io.crate.operation.scalar.string.StringCaseFunction; import io.crate.operation.scalar.systeminformation.CurrentSchemaFunction; -import io.crate.operation.scalar.systeminformation.UserFunction; import io.crate.operation.scalar.timestamp.CurrentTimestampFunction; import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.multibindings.MapBinder; -import org.elasticsearch.common.settings.Settings; import java.util.HashMap; import java.util.Map; public class ScalarFunctionModule extends AbstractModule { - private final Settings settings; private Map functions = new HashMap<>(); private Map resolver = new HashMap<>(); private MapBinder functionBinder; private MapBinder resolverBinder; - public ScalarFunctionModule(Settings settings) { - this.settings = settings; - } - public void register(FunctionImplementation impl) { functions.put(impl.info().ident(), impl); } @@ -129,7 +122,6 @@ protected void configure() { IfFunction.register(this); CurrentSchemaFunction.register(this); - UserFunction.register(this, settings); // bind all registered functions and resolver // by doing it here instead of the register functions, plugins can also use the diff --git a/sql/src/main/java/io/crate/plugin/SQLPlugin.java b/sql/src/main/java/io/crate/plugin/SQLPlugin.java index ad63c9bc4c4b..2b4f34b86e79 100644 --- a/sql/src/main/java/io/crate/plugin/SQLPlugin.java +++ b/sql/src/main/java/io/crate/plugin/SQLPlugin.java @@ -171,7 +171,7 @@ public Collection createGuiceModules() { modules.add(new SysClusterExpressionModule()); modules.add(new SysNodeExpressionModule()); modules.add(new AggregationImplModule()); - modules.add(new ScalarFunctionModule(settings)); + modules.add(new ScalarFunctionModule()); modules.add(new TableFunctionModule()); modules.add(new BulkModule()); modules.add(new SysChecksModule()); diff --git a/sql/src/test/java/io/crate/analyze/symbol/format/SymbolPrinterTest.java b/sql/src/test/java/io/crate/analyze/symbol/format/SymbolPrinterTest.java index f0306623fcca..27f50d80d627 100644 --- a/sql/src/test/java/io/crate/analyze/symbol/format/SymbolPrinterTest.java +++ b/sql/src/test/java/io/crate/analyze/symbol/format/SymbolPrinterTest.java @@ -107,15 +107,6 @@ public void testFormatFunctionFullQualifiedInputName() throws Exception { public void testFormatFunctionsWithoutBrackets() throws Exception { Symbol f = sqlExpressions.asSymbol("current_schema"); assertPrint(f, "current_schema"); - - f = sqlExpressions.asSymbol("current_user"); - assertPrint(f, "current_user"); - - f = sqlExpressions.asSymbol("session_user"); - assertPrint(f, "session_user"); - - f = sqlExpressions.asSymbol("user"); - assertPrint(f, "current_user"); } @Test diff --git a/sql/src/test/java/io/crate/operation/scalar/systeminformation/UserFunctionsTest.java b/sql/src/test/java/io/crate/operation/scalar/systeminformation/UserFunctionsTest.java deleted file mode 100644 index ec3fce04536c..000000000000 --- a/sql/src/test/java/io/crate/operation/scalar/systeminformation/UserFunctionsTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Licensed to Crate under one or more contributor license agreements. - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. Crate licenses this file - * to you under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. You may - * obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - * implied. See the License for the specific language governing - * permissions and limitations under the License. - * - * However, if you have executed another commercial license agreement - * with Crate these terms will supersede the license and you may use the - * software solely pursuant to the terms of the relevant commercial - * agreement. - */ - -package io.crate.operation.scalar.systeminformation; - -import io.crate.action.sql.Option; -import io.crate.action.sql.SessionContext; -import io.crate.exceptions.UnsupportedFeatureException; -import io.crate.metadata.Functions; -import io.crate.operation.scalar.AbstractScalarFunctionsTest; -import io.crate.operation.user.User; -import io.crate.settings.SharedSettings; -import io.crate.testing.SqlExpressions; -import org.elasticsearch.common.settings.Settings; -import org.junit.Test; - -import java.util.Collections; - -import static io.crate.testing.SymbolMatchers.isLiteral; - -public class UserFunctionsTest extends AbstractScalarFunctionsTest { - - private static final User TEST_USER = new User("testUser", Collections.emptySet()); - - private void setupFunctionsForTestUser() { - sqlExpressions = new SqlExpressions(tableSources, new SessionContext(0, Option.NONE, null, TEST_USER)); - functions = sqlExpressions.getInstance(Functions.class); - } - - @Test - public void testNormalizeCurrentUser() { - setupFunctionsForTestUser(); - assertNormalize("current_user", isLiteral("testUser"), false); - } - - @Test - public void testNormalizeSessionUser() { - setupFunctionsForTestUser(); - assertNormalize("session_user", isLiteral("testUser"), false); - } - - @Test - public void testNormalizeUser() { - setupFunctionsForTestUser(); - assertNormalize("user", isLiteral("testUser"), false); - } - - @Test - public void testCurrentUserIsAnEnterpriseFeature() { - setupNonEnterpriseFunctions(); - expectedException.expect(UnsupportedFeatureException.class); - expectedException.expectMessage("current_user function is only supported in enterprise version"); - - assertNormalize("current_user", null, false); - } - - @Test - public void testUserIsAnEnterpriseFeature() { - setupNonEnterpriseFunctions(); - expectedException.expect(UnsupportedFeatureException.class); - expectedException.expectMessage("user function is only supported in enterprise version"); - - assertNormalize("user", null, false); - } - - @Test - public void testSessionUserIsAnEnterpriseFeature() { - setupNonEnterpriseFunctions(); - expectedException.expect(UnsupportedFeatureException.class); - expectedException.expectMessage("session_user function is only supported in enterprise version"); - - assertNormalize("session_user", null, false); - } - - private void setupNonEnterpriseFunctions() { - SessionContext sessionContext = new SessionContext(0, Option.NONE, null, null); - Settings.Builder settings = Settings.builder(); - settings.put(SharedSettings.ENTERPRISE_LICENSE_SETTING.getKey(), false); - sqlExpressions = new SqlExpressions(tableSources, null, null, sessionContext, - settings.build()); - functions = sqlExpressions.getInstance(Functions.class); - } - - @Test - public void testCurrentUserForMissingUserReturnsNull() { - setupFunctionsWithoutUser(); - assertNormalize("current_user", isLiteral(null), false); - } - - @Test - public void testUserForMissingUserReturnsNull() { - setupFunctionsWithoutUser(); - assertNormalize("user", isLiteral(null), false); - } - - @Test - public void testSessionUserForMissingUserReturnsNull() { - setupFunctionsWithoutUser(); - assertNormalize("session_user", isLiteral(null), false); - } - - private void setupFunctionsWithoutUser() { - SessionContext sessionContext = new SessionContext(0, Option.NONE, null, null); - sqlExpressions = new SqlExpressions(tableSources, sessionContext); - functions = sqlExpressions.getInstance(Functions.class); - } -} diff --git a/sql/src/test/java/io/crate/testing/SqlExpressions.java b/sql/src/test/java/io/crate/testing/SqlExpressions.java index 13218a26a228..32056f987440 100644 --- a/sql/src/test/java/io/crate/testing/SqlExpressions.java +++ b/sql/src/test/java/io/crate/testing/SqlExpressions.java @@ -45,9 +45,9 @@ import io.crate.operation.tablefunctions.TableFunctionModule; import io.crate.sql.parser.SqlParser; import io.crate.sql.tree.QualifiedName; +import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.Injector; import org.elasticsearch.common.inject.ModulesBuilder; -import org.elasticsearch.common.settings.Settings; import javax.annotation.Nullable; import java.util.Collections; @@ -63,41 +63,39 @@ public class SqlExpressions { private final Functions functions; public SqlExpressions(Map sources) { - this(sources, null, null, SessionContext.SYSTEM_SESSION, Settings.EMPTY); + this(sources, null, null, SessionContext.SYSTEM_SESSION); } public SqlExpressions(Map sources, Object[] parameters) { - this(sources, null, parameters, SessionContext.SYSTEM_SESSION, Settings.EMPTY); + this(sources, null, parameters, SessionContext.SYSTEM_SESSION); } public SqlExpressions(Map sources, @Nullable FieldResolver fieldResolver) { - this(sources, fieldResolver, null, SessionContext.SYSTEM_SESSION, Settings.EMPTY); + this(sources, fieldResolver, null, SessionContext.SYSTEM_SESSION); } public SqlExpressions(Map sources, SessionContext sessionContext) { - this(sources, null, null, sessionContext, Settings.EMPTY); - } - - public SqlExpressions(Map sources, - @Nullable FieldResolver fieldResolver, - @Nullable Object[] parameters, - SessionContext sessionContext) { - this(sources, fieldResolver, parameters, sessionContext, Settings.EMPTY); + this(sources, null, null, sessionContext); } public SqlExpressions(Map sources, @Nullable FieldResolver fieldResolver, @Nullable Object[] parameters, SessionContext sessionContext, - Settings settings) { + AbstractModule... additionalModules) { ModulesBuilder modulesBuilder = new ModulesBuilder() .add(new OperatorModule()) .add(new AggregationImplModule()) - .add(new ScalarFunctionModule(settings)) + .add(new ScalarFunctionModule()) .add(new TableFunctionModule()) .add(new PredicateModule()); + if (additionalModules != null) { + for (AbstractModule module : additionalModules) { + modulesBuilder.add(module); + } + } injector = modulesBuilder.createInjector(); functions = injector.getInstance(Functions.class); expressionAnalyzer = new ExpressionAnalyzer( diff --git a/sql/src/test/java/io/crate/testing/TestingHelpers.java b/sql/src/test/java/io/crate/testing/TestingHelpers.java index b4c1ac94958a..4a1aafefa549 100644 --- a/sql/src/test/java/io/crate/testing/TestingHelpers.java +++ b/sql/src/test/java/io/crate/testing/TestingHelpers.java @@ -47,7 +47,6 @@ import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.inject.ModulesBuilder; import org.elasticsearch.common.xcontent.NamedXContentRegistry; -import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; @@ -155,15 +154,11 @@ public static String mapToSortedString(Map map) { } public static Functions getFunctions() { - return getFunctions(Settings.EMPTY); - } - - public static Functions getFunctions(Settings settings) { return new ModulesBuilder() .add(new AggregationImplModule()) .add(new PredicateModule()) .add(new TableFunctionModule()) - .add(new ScalarFunctionModule(settings)) + .add(new ScalarFunctionModule()) .add(new OperatorModule()).createInjector().getInstance(Functions.class); }