I created a custom PostgreSQL function:
create function delete_classes() returns void as
$$
DELETE FROM ...;
$$ language sql;
I would like to call this function with Spring`s JDBCTemplate. I tried the following:
#Repository
class Repository {
private final JdbcTemplate template; // initialized in constructor
public void deleteClasses() {
template.update("select delete_classes()");
}
}
I get the following error:
Caused by: org.springframework.dao.DataIntegrityViolationException:
PreparedStatementCallback; SQL [select delete_classes()];
A result was returned when none was expected.;
nested exception is org.postgresql.util.PSQLException:
A result was returned when none was expected.
The PostgreSQL function delete_classes returns void, so I am not really sure what is meant here. The DELETE statement has no RETURNING ... clause.
What is the correct way to execute the function?
update
I tried the following (execute instead of update):
#Repository
class Repository {
private final JdbcTemplate template; // initialized in constructor
public void deleteClasses() {
template.execute("select delete_classes()", statement -> null);
}
}
Here, this implements a PreparedStatementCallback in lambda-fashion which just returns null.
The function delete_classes is not called now.
Related
I'm using:
Jooq 3.13.2
Kotlin 1.3.71
Spring boot 2.2.6.RELESE
Java 11
I was able to generate Jooq classes and execute a simple query:
class StoryCustomRepositoryImpl #Autowired constructor(
private val dslContext: DSLContext
): StoryCustomRepository {
override fun findEmployeeStories(pageable: Pageable) {
return dslContext.select(STORY.ID, STORY.DESCRIPTION)
.from(STORY)
.forEach { println($it[STORY.ID]) }
}
}
When I try to add a bit more complex logic by adding join, compilation is failing:
class StoryCustomRepositoryImpl #Autowired constructor(
private val dslContext: DSLContext
): StoryCustomRepository {
override fun findEmployeeStories(pageable: Pageable) {
return dslContext.select(STORY.ID, STORY.DESCRIPTION)
.from(STORY)
.join(USERS).on(USERS.ID.eq(STORY.CREATED_BY))
.forEach { println($it[STORY.ID]) }
}
}
Compilation fails on following line .join(USERS).on(USERS.ID.eq(STORY.CREATED_BY))
Error:
None of the following functions can be called with the arguments supplied:
public abstract fun eq(p0: Int!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: Field<Int!>!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: QuantifiedSelect<out Record1<Int!>!>!): Condition! defined in org.jooq.TableField
public abstract fun eq(p0: Select<out Record1<Int!>!>!): Condition! defined in org.jooq.TableField
I was following this tutorial: https://blog.jooq.org/2017/05/18/10-nice-examples-of-writing-sql-in-kotlin-with-jooq/
Edit:
It looks like the issue is that STORY.CREATED_BY is type of Long, while USERS.ID is type of Integer. I'm not sure what needs to be changed to be able to fix this.
Thank you
You should probably change the type of all of these ID columns and their reference to be the same, i.e. BIGINT.
As a quick workaround, you can use Field.coerce(). I would prefer that over Field.cast(). The difference is that coerce() does not have any effect on the generated SQL (which you want to avoid to get better index usage), whereas cast() translates to the SQL CAST() function.
I’m dealing with following issue with Kotlin/Java Compiler.
Imagine following scenario: let First be a Java class with a final function and Second be a Kotlin class extending First with a function of the same name like the final function in First class, example:
// Java class
class First {
final void foo() { }
}
// Kotlin class
class Second: First() {
fun foo() { }
}
Obviously, it’s wrong because the final function foo() can not be overridden. However, compilation pass successfully and in run-time I get java.lang.LinkageError: Method void Second.foo() overrides final method in class First.
Is this correct behavior of compiler? I supposed that there will be some validations for this case. Thank you!
I'm using Apache Calcite to validate SQL. I add tables and UDFs dynamically.
The problem is when I add a UDF with variable number parameter, the validator can not find this function.
Version of Calcite is 1.18.0
And this is my code.
TestfuncFunction.java
public class TestfuncFunction {
public String testfunc(String... arg0) {
return null;
}
}
Add UDF
Function schemafunction = ScalarFunctionImpl.create(TestfuncFunction.class),"testfunc");
SchemaPlus schemaPlus = Frameworks.createRootSchema(true);
schemaPlus.add("testfunc", schemafunction);
SQL
select testfunc(field1, field2) from test_table
testfunc is a ScalarFunction with variable number parameter,field1 and field2 are columns of test_table. So this is a legal SQL. But I got this CalciteContextException when validating:
No match found for function signature testfunc(<CHARACTER>, <CHARACTER>)
I tryed to change my sql into one parameter like this:
select testfunc(field1) from test_table
and got this exception
java.lang.AssertionError: No assign rules for OTHER defined
at org.apache.calcite.sql.type.SqlTypeAssignmentRules.canCastFrom(SqlTypeAssignmentRules.java:386)
at org.apache.calcite.sql.type.SqlTypeUtil.canCastFrom(SqlTypeUtil.java:864)
at org.apache.calcite.sql.SqlUtil.lambda$filterRoutinesByParameterType$4(SqlUtil.java:554)
...
It seems that calcite transform java array type into SqlTypeName.OTHER.
I have tryed to override method "createJavaType" in JavaTypeFactoryImpl like this:
private static class CustomJavaTypeFactoryImpl extends JavaTypeFactoryImpl {
#Override
public RelDataType createJavaType(Class clazz) {
if (clazz.isArray()) {
return new ArraySqlType(super.createJavaType(clazz.getComponentType()), true);
}
return super.createJavaType(clazz);
}
}
but it did not work.
Do Calcite support UDF with variable number parameter, and what should I do.
class Test {
int a = 100;
System.out.println(a);
}
class Demo {
public static void main(String args[]) {
Test t = new Test();
}
}
I'm new to programming. I found this code when I'm practicing. I don't understand why I'm getting this error.
Here is the error I'm getting.
Demo.java:3: error: <identifier> expected
System.out.println(a);
^
Demo.java:3: error: <identifier> expected
System.out.println(a);
^
2 errors
Compilation failed.
Can you guys explain why I'm getting this error?
You can't call a method directly from the java class body.
Create a constructor in your Test class, and put the print in it :
class Test {
int a = 100;
public Test() {
System.out.println(a);
}
}
Note that if for some reason you really want a statement to be executed when the class is loaded without using a constructor, you can define a static block, here an example :
class Test {
static int a = 100;
static {
System.out.println(a);
}
}
However, this is just for reference and really not needed in your case.
From Declaring Classes in the Java tutorial:
In general, class declarations can include these components, in order:
Modifiers such as public, private, and a number of others that you will encounter later.
The class name, with the initial letter capitalized by convention.
The name of the class's parent (superclass), if any, preceded by the keyword extends. A class can only extend (subclass) one parent.
A comma-separated list of interfaces implemented by the class, if any, preceded by the keyword implements. A class can implement more than one interface.
The class body, surrounded by braces, {}.
You can't make any function calls outside of a method declaration.
I have the following code:
public void someMethod() {
Set<Foo> fooSet = bar.getFoos();
for(Foo foo: fooSet) {
foo.doSomething();
}
}
and I want to test this using JMockit but am unsure how to get to return a collection of a certain type and size.
The following test for my code throws a null pointer exception for hashcode when trying to add foo to the set of foos.
#Test
public void someTestMethod()
{
new Expectations()
{
#Mocked Bar bar;
#Mocked Foo foo;
Set<Foo> foos = new HashSet<Foo>();
foos.add(foo);
bar.getFoos(); returns(foos);
foo.doSomething();
};
new SomeClass().someMethod();
}
How should this be done?
I'm not exactly sure how to answer your question because I don't understand what you are trying to test, but I believe you want something like this:
#Test
public void someTestMethod(#Mocked(methods="getFoos")final Bar mockedBar
#Mocked(methods="doSomething")final Foo mockedFoo {
final Set<Foo> foos = new HashSet<Foo>();
foos.add(new Foo());
new Expectations() {
{
mockedBar.getFoos(); returns(foos);
mockedFoo.doSomething();
}
};
new SomeClass().someMethod();
}
Using this, JMockit will mock the call to getFoos and return the Set foos. If you look at the parameters I am passing in, I am doing a partial mock of the Bar and Foo classes (I am only mocking the calls to the getFoos and doSomething method). I also noticed you are missing a set of braces in your new Expectations block, so that could definitely cause you some problems. One other issue you have to keep in mind is that using Expectations as opposed to NonStrictExpectations will cause an error if you put more than one object in the Set foos because it is only expecting one call to doSomething. If you make a test case where foos has more than one object in it you could either use NonStrictExpectations or use the minTimes and maxTimes to specify invocation count constraints