Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions gradle/verification-metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<ignored-key id="0C27E8FAC93B3B19" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="0CA7139CBC7026F9" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="1063FE98BCECB758" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="1364C5E2DF3E99C5" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="156E8DA37ABC7C91" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="1861C322C56014B2" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="1C8D5EF0DF2B70D4" reason="Key couldn't be downloaded from any key server"/>
Expand All @@ -77,10 +78,13 @@
<ignored-key id="3B14D24C5988C977" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="3C1381C7D09AF9E1" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="3FAAD2CD5ECBB314" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="4406B84C1661DCD1" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="4783A0225D80620F" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="4ECE492B63E38ACF" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="55101494C452D7A2" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="58BD11D32974088F" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="631ECF66932B28BA" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="66F8E4860BF74983" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="70F09CC6B876884A" reason="Key couldn't be downloaded from any key server"/>
<ignored-key id="74DAFDFD6DAE2441" reason="Key not available on any key server"/>
<ignored-key id="79E193516BE7998F" reason="Key couldn't be downloaded from any key server"/>
Expand Down Expand Up @@ -723,6 +727,11 @@
<sha512 value="e8995ff1332e3d52a33117f84c83b1e4bab1506817f8ef6f68945ca1aa265fdc325e5cfd7a7fcd500a899456d258820c046db48ed4b9853c3ceec89bca3ec9db" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.h2database" name="h2" version="2.4.240">
<artifact name="h2-2.4.240.jar">
<sha256 value="29b70e427cc1c40cdc376283adbb0cc62853073797bb5fe5761f81fe73d57ce0" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
</artifact>
</component>
<component group="com.h3xstream.findsecbugs" name="findsecbugs-plugin" version="1.13.0">
<artifact name="findsecbugs-plugin-1.13.0.jar">
<pgp value="CFC10B69382CBCF5387E51484ECE492B63E38ACF"/>
Expand Down Expand Up @@ -1057,6 +1066,11 @@
<pgp value="48B086A7D843CFA258E83286928FBF39003C0425"/>
</artifact>
</component>
<component group="io.r2dbc" name="r2dbc-spi" version="1.0.0.RELEASE">
<artifact name="r2dbc-spi-1.0.0.RELEASE.jar">
<sha256 value="a5846c59fea336431a4ae72ca14edbf5299b78486fa308eafb383f4ae0ea74e5" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
</artifact>
</component>
<component group="io.reactivex.rxjava3" name="rxjava" version="3.1.10">
<artifact name="rxjava-3.1.10.jar">
<pgp value="E9CC3CD1AE59E851E4DB3FA350FFD7487D34B5B9"/>
Expand Down Expand Up @@ -2737,6 +2751,11 @@
<sha512 value="ac2ced8c9308a6f1606dbd4e15dce428d0fecef9bbd16d3a350368067af7a4aab3773242f46a7d89b9f7422942ba4fc10582232977a3d47240686f8c1a5e66f6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.jooq" name="jooq" version="3.19.36">
<artifact name="jooq-3.19.36.jar">
<sha256 value="3f155f81c017a1ab456959cedb5597bfe52a893115b7dcd91514c0a5b56138dd" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
</artifact>
</component>
<component group="org.jparsec" name="jparsec" version="3.1">
<artifact name="jparsec-3.1.jar">
<sha512 value="0b5b15349b63d7fe1cb6880e8abc9bed54750f1207d978f85cd8475890c0a40d011917e586047b75620f5df42ed41f0e524d9446a266c1e8b80201907094c17a" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
Expand Down Expand Up @@ -3227,6 +3246,11 @@
<sha512 value="adcc480f68828ffd68d03846be852988b595c2e1bb69224d273578dd6c2ad2773edfe96625a7c00bc40ae0f2d1cac8412eaa54b88cc8e681b0b4c0ee3b082333" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.reactivestreams" name="reactive-streams" version="1.0.3">
<artifact name="reactive-streams-1.0.3.jar">
<sha256 value="1dee0481072d19c929b623e155e14d2f6085dc011529a0a0dbefc84cf571d865" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
</artifact>
</component>
<component group="org.reactivestreams" name="reactive-streams" version="1.0.4">
<artifact name="reactive-streams-1.0.4.jar">
<pgp value="50A628FFAF58480736B1079FD1031D14464180E0"/>
Expand Down
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def subprojects = [
'groovy-jsr223',
'groovy-logging-test',
'groovy-ginq',
'groovy-ginq-sql',
'groovy-http-builder',
'groovy-markdown',
'groovy-macro',
Expand Down
46 changes: 46 additions & 0 deletions subprojects/groovy-ginq-sql/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.
*/
plugins {
id 'org.apache.groovy-library'
}

dependencies {
api rootProject
api projects.groovyGinq
api projects.groovySql
compileOnly "org.jooq:jooq:${versions.jooq}" // used by the optional jooq-sql provider
testImplementation projects.groovyTest
testImplementation "org.jooq:jooq:${versions.jooq}"
testImplementation 'com.h2database:h2:2.4.240'
}

groovyLibrary {
optionalModule()

withoutBinaryCompatibilityChecks()
}

// GINQ macros expand at test-compile time using this module's classes, so the
// provider implementation (not just its ABI) is a genuine input; without this,
// compilation avoidance and the build cache can reuse test classes containing
// stale macro expansions
tasks.named('compileTestGroovy') {
inputs.files(tasks.named('compileGroovy').flatMap { it.destinationDirectory })
.withPropertyName('sqlProviderImplementation')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.
*/
package org.apache.groovy.ginq.provider.sql

import groovy.transform.CompileStatic
import org.apache.groovy.ginq.GinqGroovyMethods
import org.apache.groovy.ginq.dsl.GinqAstVisitor
import org.apache.groovy.ginq.dsl.GinqSyntaxError
import org.apache.groovy.ginq.dsl.SyntaxErrorReportable
import org.apache.groovy.ginq.dsl.expression.AbstractGinqExpression
import org.apache.groovy.ginq.dsl.expression.FromExpression
import org.apache.groovy.ginq.dsl.expression.GinqExpression
import org.apache.groovy.ginq.dsl.expression.GroupExpression
import org.apache.groovy.ginq.dsl.expression.HavingExpression
import org.apache.groovy.ginq.dsl.expression.JoinExpression
import org.apache.groovy.ginq.dsl.expression.LimitExpression
import org.apache.groovy.ginq.dsl.expression.OnExpression
import org.apache.groovy.ginq.dsl.expression.OrderExpression
import org.apache.groovy.ginq.dsl.expression.SelectExpression
import org.apache.groovy.ginq.dsl.expression.SetOperationExpression
import org.apache.groovy.ginq.dsl.expression.ShutdownExpression
import org.apache.groovy.ginq.dsl.expression.WhereExpression
import org.apache.groovy.ginq.provider.sql.ir.SqlQueryNode
import org.apache.groovy.ginq.provider.sql.render.AnsiDialect
import org.apache.groovy.ginq.provider.sql.render.RenderedSql
import org.apache.groovy.ginq.provider.sql.render.SqlRenderer
import org.apache.groovy.ginq.provider.sql.runtime.SqlGinqRuntime
import org.apache.groovy.lang.annotation.Incubating
import org.codehaus.groovy.GroovyBugError
import org.codehaus.groovy.ast.ClassHelper
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.expr.Expression
import org.codehaus.groovy.ast.expr.ListExpression
import org.codehaus.groovy.ast.expr.MethodCallExpression
import org.codehaus.groovy.control.SourceUnit

import static org.codehaus.groovy.ast.tools.GeneralUtils.args
import static org.codehaus.groovy.ast.tools.GeneralUtils.callX
import static org.codehaus.groovy.ast.tools.GeneralUtils.classX
import static org.codehaus.groovy.ast.tools.GeneralUtils.constX

/**
* The native SQL provider: transforms a GINQ query into a call executing the
* equivalent SQL, rendered at compile time with all user values bound as
* positional parameters, against the configured {@code dataSource}.
*
* @since 6.0.0
*/
@Incubating
@CompileStatic
class GinqSqlWalker implements GinqAstVisitor<Expression>, SyntaxErrorReportable {
private final SourceUnit sourceUnit
private Map<String, String> configuration = [:]
private Map<String, Expression> configurationExpressions = [:]

GinqSqlWalker(SourceUnit sourceUnit) {
this.sourceUnit = sourceUnit
}

@Override
SourceUnit getSourceUnit() {
return sourceUnit
}

@Override
Expression visit(AbstractGinqExpression expression) {
if ('true' == configuration.get(GinqGroovyMethods.CONF_PARALLEL)) {
error("`parallel` is not supported by the ${providerName} provider", expression)
}
if (expression instanceof ShutdownExpression) {
error("`shutdown` is not supported by the ${providerName} provider", expression)
}
Expression dataSourceExpr = configurationExpressions.get(GinqGroovyMethods.CONF_DATA_SOURCE)
if (dataSourceExpr == null) {
error("the ${providerName} provider requires a `dataSource`, e.g. GQ(provider: '${providerName}', dataSource: db) {...}; " +
'note that `@GQ` does not support `dataSource`', expression)
}
validateOptions(expression)

SqlQueryNode queryNode = new GinqToSqlTranslator(sourceUnit).translate(expression)
RenderedSql renderedSql = renderSql(queryNode, expression)

MethodCallExpression executeCall = callX(
classX(SQL_GINQ_RUNTIME_TYPE),
'execute',
args(dataSourceExpr, constX(renderedSql.sql), new ListExpression(renderedSql.parameters)))
executeCall.setSourcePosition(expression)
return executeCall
}

/**
* Returns the provider name used in diagnostics.
*/
protected String getProviderName() {
return 'native-sql'
}

/**
* Validates provider-specific options.
*/
protected void validateOptions(AbstractGinqExpression expression) {
if (configuration.containsKey('dialect')) {
error('`dialect` is only supported by the jooq-sql provider', expression)
}
}

/**
* Renders the translated query to SQL text plus ordered parameters.
*/
protected RenderedSql renderSql(SqlQueryNode queryNode, AbstractGinqExpression expression) {
return new SqlRenderer(new AnsiDialect()).render(queryNode)
}

@Override
Expression visitGinqExpression(GinqExpression ginqExpression) {
return visit(ginqExpression)
}

@Override
Expression visitSetOperationExpression(SetOperationExpression setOperationExpression) {
return visit(setOperationExpression)
}

@Override
Expression visitShutdownExpression(ShutdownExpression shutdownExpression) {
return visit(shutdownExpression)
}

@Override
Expression visitFromExpression(FromExpression fromExpression) {
throw new GroovyBugError('clauses are translated by GinqToSqlTranslator')
}

@Override
Expression visitJoinExpression(JoinExpression joinExpression) {
throw new GroovyBugError('clauses are translated by GinqToSqlTranslator')
}

@Override
Expression visitOnExpression(OnExpression onExpression) {
throw new GroovyBugError('clauses are translated by GinqToSqlTranslator')
}

@Override
Expression visitWhereExpression(WhereExpression whereExpression) {
throw new GroovyBugError('clauses are translated by GinqToSqlTranslator')
}

@Override
Expression visitGroupExpression(GroupExpression groupExpression) {
throw new GroovyBugError('clauses are translated by GinqToSqlTranslator')
}

@Override
Expression visitHavingExpression(HavingExpression havingExpression) {
throw new GroovyBugError('clauses are translated by GinqToSqlTranslator')
}

@Override
Expression visitOrderExpression(OrderExpression orderExpression) {
throw new GroovyBugError('clauses are translated by GinqToSqlTranslator')
}

@Override
Expression visitLimitExpression(LimitExpression limitExpression) {
throw new GroovyBugError('clauses are translated by GinqToSqlTranslator')
}

@Override
Expression visitSelectExpression(SelectExpression selectExpression) {
throw new GroovyBugError('clauses are translated by GinqToSqlTranslator')
}

@Override
void setConfiguration(Map<String, String> configuration) {
this.configuration = configuration
}

@Override
Map<String, String> getConfiguration() {
return configuration
}

@Override
void setConfigurationExpressions(Map<String, Expression> configurationExpressions) {
this.configurationExpressions = configurationExpressions
}

@Override
Map<String, Expression> getConfigurationExpressions() {
return configurationExpressions
}

protected void error(String message, org.codehaus.groovy.ast.ASTNode node) {
collectSyntaxError(new GinqSyntaxError(message, node.lineNumber, node.columnNumber))
}

private static final ClassNode SQL_GINQ_RUNTIME_TYPE = ClassHelper.makeCached(SqlGinqRuntime)
}
Loading
Loading