I have a simple query on a table which queries with the primary key.
dslContext.select(XXX.NAME)
.from(XXX)
.where(
XXX.ID.eq(id)
.and(XXX.LEVEL.eq(2))
.and(XXX.NAME.isNotNull())
)
.fetchOne().into(String.class);
In my case for a particular id, the query results in a empty set. But jooq seems to throw a NPE. When I further investigated, fetchOne() calls CursorImpl.fetchOne(). This checks the size of the result and if it is not 1, it returns null. I have a chained into(String.class) which gets called on this null value and hence resulting in NPE.
I don't want to call fetch() and iterate over the results/get the first element of the list.
Is there an alternative way of writing the query such that it will throw a org.jooq.exception.NoDataFoundException if there is no data?
Why a NullPointerException is being thrown
Technically, jOOQ doesn't throw a NullPointerException. Your calling into(Class) on a potentially null record does, as documented also in the Javadoc of ResultQuery.fetchOne()
Returns:
The resulting record or null if the query returns no records.
Throwing a NoDataFoundException.
You could use fetchOptional() and then use orElseThrow():
String string =
dslContext.select(XXX.NAME)
.from(XXX)
.where(
XXX.ID.eq(id)
.and(XXX.LEVEL.eq(2))
.and(XXX.NAME.isNotNull())
)
.fetchOptional()
.orElseThrow(() -> new NoDataFoundException("..."))
.into(String.class);
Note, there's a pending feature request for such a built-in fetch method: https://github.com/jOOQ/jOOQ/issues/5411
In jOOQ 3.10, you will be able to write:
String string =
dslContext.select(XXX.NAME)
.from(XXX)
.where(
XXX.ID.eq(id)
.and(XXX.LEVEL.eq(2))
.and(XXX.NAME.isNotNull())
)
.fetchSingle() // Might throw a NoDataFoundException but never returns null
.into(String.class);
Related
I want to catch and handle SAPSQL_DATA_LOSS in my ABAP code.
I tried this:
try.
SELECT *
FROM (rtab_name) AS rtab
WHERE (sub_condition)
into table #<sub_result>
.
catch SAPSQL_DATA_LOSS into error.
...
endtry.
But above code is not valid. I get this message:
Type "SAPSQL_DATA_LOSS" is not valid
And I tried this:
catch SYSTEM-EXCEPTIONS SAPSQL_DATA_LOSS = 123.
SELECT *
...
.
endcatch.
if sy-subrc = 123.
...
endif.
But above code gives me:
Instead of "SAPSQL_DATA_LOSS" expected "system-exception" (translated from german to english by me)
How to catch SAPSQL_DATA_LOSS?
This question is not about "why does this exception happen?". This is already solved. My code should handle the exception.
SAPSQL_DATA_LOSS is a runtime error.
As SAPSQL_DATA_LOSS is not a class-based exception, it is not possible to catch it using try catch.
As SAPSQL_DATA_LOSS is not a catchable runtime error, it is not possible to catch it using try catch SYSTEM-EXCEPTIONS.
see the below catchable runtime errors.
https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abenueb-abfb-sysexc.htm
After some tries I can propose you a possible solution.
This is a workaround:
I don't know if it can be applied to your case, since it needs the select statement to be wrapped into an RFC function module !
The main point is that a short dump (message type X) CAN be handled in RFC calls.
So using an RFC (CALL FUNCTION 'xxxxx' destination 'NONE' for example) and using special exception SYSTEM_FAILURE, the system does not terminate the caller program, but instead it returns a SY-SUBRC > 0 with the Short dump informations in system message fields (SY-MSGxx).
STEPS
Create a Function module (RFC enabled) with your select statement input + the row type of the result table. (All parameters passed by value)
You need this last parameter since generic tables can't be passed in RFC (no "TYPE ANY TABLE" allowed)
FUNCTION Z_DYN_SEL .
*"----------------------------------------------------------------------
*"*"Local interface:
*" IMPORTING
*" VALUE(RTAB_NAME) TYPE TABNAME16
*" VALUE(SUB_CONDITION) TYPE STRING
*" VALUE(RESULT_TYPE) TYPE STRING
*"----------------------------------------------------------------------
* RTAB_NAME: DB Table
* SUB_CONDITION: WHERE Condition
* RESULT_TYPE: The ROW type of the internal table
field-symbols <sub_result> type any table.
* DEFINE LOCAL DYNAMIC TABLE TO STORE THE RESULT
data: lr_res type ref to data.
create data lr_res type standard table of (result_type).
assign lr_res->* to <sub_result>.
* DYNAMIC SELECT
select *
from (rtab_name) as rtab
where (sub_condition)
into table #<sub_result>.
* EXPORT RESULT TO A MEMORY ID, SO IT CAN BE RETRIEVED BY CALLER
export res = <sub_result> to memory id 'RES'.
Main program:
In this caller example some parameters are passed to the RFC.
KTOKD field (should be 4 chars long) is passed with a char10 value (producing your short dump).
If ANY Dump is triggered inside the function, we can now handle it.
If everything went fine, IMPORT result from the EXPORT statement inside the RFC
field-symbols <sub_result> type any table.
data: lr_res type ref to data.
create data lr_res type standard table of KNA1.
assign lr_res->* to <sub_result>.
data lv_msg type char255.
call function 'Z_DYN_SEL' destination 'NONE'
exporting
rtab_name = 'KNA1'
sub_condition = `KTOKD = 'D001xxxxxx'`
result_type = 'KNA1'
exceptions
system_failure = 1 message lv_msg.
if sy-subrc = 0.
import res = <sub_result> from memory id 'RES'.
else.
write: / lv_msg.
write : / sy-msgid, sy-msgno, sy-msgty, sy-msgv1, sy-msgv2, sy-msgv3, sy-msgv4.
endif.
RESULTS
After the RFC call in case of a short dump in the select statement, the program is not terminated and the following pieces of information are available
SY-SUBRC = 1
lv_msg is the error text (Data was lost while copying a value.)
Sy-msgid = 00
Sy-msgno = '341'
Sy-msgty = 'X'
Sy-msgv1 = 'SAPSQL_DATA_LOSS'
Using the example from the Spring docs, I'm trying to return a value from a mySQL function. I keep getting the error Can't set IN parameter for return value of stored function call;.
I created a mySQL function that works fine (ran in MySQL Workbench). I've written a SimpleJdbcCall statement, set up the parameters as per Spring docs example but consistently get this error. If I turn the function into a procedure, the code works, I just have to retrieve the return value from the result set.
I used https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch13s05.html, section 13.5.8 as reference.
CREATE FUNCTION `ScenarioRegistration`(
environment VARCHAR(45),
username VARCHAR(15),
scenario_name VARCHAR(45)) RETURNS int(11)
A couple of SELECT statements followed by an INSERT then
RETURN scenario_id; // The inserted id
Java code:
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(getJdbcTemplate())
.withFunctionName("ScenarioRegistration")
.withoutProcedureColumnMetaDataAccess();
simpleJdbcCall.addDeclaredParameter(new SqlParameter("environment"
,Types.VARCHAR));
simpleJdbcCall.addDeclaredParameter(new SqlParameter("username"
,Types.VARCHAR));
simpleJdbcCall.addDeclaredParameter(new SqlParameter("scenario_name"
,Types.VARCHAR));
SqlParameterSource parameters = new MapSqlParameterSource()
.addValue("environment", environment)
.addValue("username", username)
.addValue("scenario_name", scenario);
simpleJdbcCall.setReturnValueRequired(true);
Integer scenario_id = simpleJdbcCall.executeFunction(
Integer.class, parameters);
All I want the routine to do is give me back the id of the newly inserted scenario.
What I get is:
SQL [{? = call scenarioregistration(?, ?)}]; Can't set IN parameter for return value of stored function call.
I find it interesting that it's taken my THREE input values and changed them to an output and TWO input values.
Anyone enlighten me as to the problem and how to fix it?
Thanks,
Steven.
I would refer to the latest docs here for your answer. It appears Spring is trying to infer the output because you didn't explicity specify one.
Per the docs above there are two valid approaches on calling the desired function with the SimpleJdbcCall:
Inferred Parameters
Because you've specified withoutProcedureColumnMetaDataAccess, Spring isn't going to look and see what the ins/outs are to your function. If you want it easy, just don't specify that and you should be able to do:
SqlParameterSource parameters = new MapSqlParameterSource()
.addValue("environment", environment)
.addValue("username", username)
.addValue("scenario_name", scenario);
Integer scenarioId = new SimpleJdbcCall(getJdbcTemplate())
.withFunctionName("ScenarioRegistration")
.executeFunction(Integer.class, parameters);
Explicit Parameters
If you want to keep withoutProcedureColumnMetaDataAccess turned off for whatever reason, you can do:
Integer scenarioId = new SimpleJdbcCall(getJdbcTemplate)
.withFunctionName("ScenarioRegistration")
.withoutProcedureColumnMetaDataAccess()
.useInParameterNames("environment", "username", "scenario_name")
.declareParameters(
new SqlOutParameter("scenario_id", Types.NUMERIC),
new SqlParameter("environment", Types.VARCHAR),
new SqlParameter("username", Types.VARCHAR),
new SqlParameter("scenario_name", Types.VARCHAR)
).executeFunction(Integer.class, parameters);
Note: It appears that order is critical in this example. The output parameter should be declared first, and the subsequent named IN parameters come last. That is, the order of the parameters ? are ordinal in [{? = call scenarioregistration(?, ?, ?)}])
Alternative NamedParameterJdbcTemplate Solution
Another way to invoke your function is via an actual JDBC call. This could hypothetically save you the grief of using the fine tuning of the SimpleJdbcCall.
Integer scenarioId = namedParameterJdbcTemplate.queryForObject(
"SELECT ScenarioRegistration(:environment, :username, :scenario_name)",
parameters,
Integer.class);
I tried to implement the akka-http rest example provided at
https://github.com/ArchDev/akka-http-rest
but I'm stuck with the
slick.SlickException: This DBMS allows only a single column to be returned from an INSERT, and that column must be an AutoInc column.
at slick.jdbc.JdbcStatementBuilderComponent$JdbcCompiledInsert.buildReturnColumns(JdbcStatementBuilderComponent.scala:67)
Here is the Scala Code:
Signup API:
path("signUp") {
pathEndOrSingleSlash {
post {
entity(as[UsernamePasswordEmail]) { userEntity =>
complete(Created -> signUp(userEntity.username, userEntity.email, userEntity.password))
}
}
}
}
AuthService.scala
def signUp(login: String, email: String, password: String): Future[AuthToken] =
authDataStorage
.saveAuthData(AuthData(UUID.randomUUID().toString, login, email, password.sha256.hex))
.map(authData => encodeToken(authData.id))
AuthDataStorage.scala
...
override def saveAuthData(authData: AuthData): Future[AuthData] =
db.run((auth returning auth).insertOrUpdate(authData)).map(_ => authData)
...
Since I'm new to Scala and Slick, can anyway provide the information why this exception is occurring even though I've defined O.AutoInc in Model. I'm using MySQL RDBMS
The problem is with returning auth. Instead of returning auth i.e complete object, Just return the auto-increment Id id. Slick does not support returning the complete object, though it compiles correctly. It does not generate a valid sql query.
Once you can get access to the auto-increment id then you can build the AuthData using the argument of the function.
Code:
(auth returning auth.map(_.id)).insertOrUpdate(authData)).map(id => authData.copy(id = id))
The exception is the result of a MySQL behavior. As the Slick documentation states:
Many database systems only allow a single column to be returned which must be the table’s auto-incrementing primary key. If you ask for other columns a SlickException is thrown at runtime (unless the database actually supports it).
Change the saveAuthData method to return the id column on an upsert:
override def saveAuthData(authData: AuthData): Future[AuthData] =
db.run((auth returning auth.map(_.id)).insertOrUpdate(authData))
.map(idFromDb => authData.copy(id = idFromDb.getOrElse(authData.id)))
In the above code, idFromDb is a Some[Int] for an insert and a None for an update.
I was wondering why this is valid go code:
func FindUserInfo(id string) (Info, bool) {
it, present := all[id]
return it, present
}
but this isn't
func FindUserInfo(id string) (Info, bool) {
return all[id]
}
is there a way to avoid the temporary variables?
To elaborate on my comment, the Effective Go mentions that the multi-value assignment from accessing a map key is called the "comma ok" pattern.
Sometimes you need to distinguish a missing entry from a zero value. Is there an entry for "UTC" or is that the empty string because it's not in the map at all? You can discriminate with a form of multiple assignment.
var seconds int
var ok bool
seconds, ok = timeZone[tz]
For obvious reasons this is called the “comma ok” idiom. In this example, if tz is present, seconds will be set appropriately and ok will be true; if not, seconds will be set to zero and ok will be false.
Playground demonstrating this
We can see that this differs from calling a regular function where the compiler would tell you that something is wrong:
package main
import "fmt"
func multiValueReturn() (int, int) {
return 0, 0
}
func main() {
fmt.Println(multiValueReturn)
asgn1, _ := multiValueReturn()
asgn2 := multiValueReturn()
}
On the playground this will output
# command-line-arguments
/tmp/sandbox592492597/main.go:14: multiple-value multiValueReturn() in single-value context
This gives us a hint that it may be something the compiler is doing. Searching the source code for "commaOk" gives us a few places to look, including types.unpack
At the time of writing this it this the method's godoc reads:
// unpack takes a getter get and a number of operands n. If n == 1, unpack
// calls the incoming getter for the first operand. If that operand is
// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a
// function call, or a comma-ok expression and allowCommaOk is set, the result
// is a new getter and operand count providing access to the function results,
// or comma-ok values, respectively. The third result value reports if it
// is indeed the comma-ok case. In all other cases, the incoming getter and
// operand count are returned unchanged, and the third result value is false.
//
// In other words, if there's exactly one operand that - after type-checking
// by calling get - stands for multiple operands, the resulting getter provides
// access to those operands instead.
//
// If the returned getter is called at most once for a given operand index i
// (including i == 0), that operand is guaranteed to cause only one call of
// the incoming getter with that i.
//
The key bits of this being that this method appears to determine whether or not something is actually a "comma ok" case.
Digging into that method tells us that it will check to see if the mode of the operands is indexing a map or if the mode is set to commaok (where this is defined does give us many hints on when it's used, but searching the source for assignments to commaok we can see it's used when getting a value from a channel and type assertions). Remember the bolded bit for later!
if x0.mode == mapindex || x0.mode == commaok {
// comma-ok value
if allowCommaOk {
a := [2]Type{x0.typ, Typ[UntypedBool]}
return func(x *operand, i int) {
x.mode = value
x.expr = x0.expr
x.typ = a[i]
}, 2, true
}
x0.mode = value
}
allowCommaOk is a parameter to the function. Checking out where unpack is called in that file we can see that all callers pass false as an argument. Searching the rest of the repository leads us to assignments.go in the Checker.initVars() method.
l := len(lhs)
get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
Since it seems that we can only use the "comma ok" pattern to get two return values when doing a multi-value assignment this seems like the right place to look! In the above code the length of the left hand side is checked, and when unpack is called the allowCommaOk parameter is the result of l == 2 && !returnPos.IsValid(). The !returnPos.IsValid() is somewhat confusing here as that would mean that the position has no file or line information associated with it, but we'll just ignore that.
Further down in that method we've got:
var x operand
if commaOk {
var a [2]Type
for i := range a {
get(&x, i)
a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
}
check.recordCommaOkTypes(rhs[0], a)
return
}
So what does all of this tell us?
Since the unpack method takes an allowCommaOk parameter that's hardcoded to false everywhere except in assignment.go's Checker.initVars() method, we can probably assume that you will only ever get two values when doing an assignment and have two variables on the left-hand side.
The unpack method will determine whether or not you actually do get an ok value in return by checking if you are indexing a slice, grabbing a value from a channel, or doing a type assertion
Since you can only get the ok value when doing an assignment it looks like in your specific case you will always need to use variables
You may save a couple of key strokes by using named returns:
func FindUserInfo(id string) (i Info, ok bool) {
i, ok = all[id]
return
}
But apart from that, I don't think what you want is possible.
Simply put: the reason why your second example isn't valid Go code is because the language specification says so. ;)
Indexing a map only yields a secondary value in an assignment to two variables. Return statement is not an assignment.
An index expression on a map a of type map[K]V used in an assignment or initialization of the special form
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
yields an additional untyped boolean value. The value of ok is true if the key x is present in the map, and false otherwise.
Furthermore, indexing a map is not a "single call to a multi-valued function", which is one of the three ways to return values from a function (the second one, the other two not being relevant here):
There are three ways to return values from a function with a result type:
The return value or values may be explicitly listed in the "return" statement. Each expression must be single-valued and assignable to the corresponding element of the function's result type.
The expression list in the "return" statement may be a single call to a multi-valued function. The effect is as if each value returned from that function were assigned to a temporary variable with the type of the respective value, followed by a "return" statement listing these variables, at which point the rules of the previous case apply.
The expression list may be empty if the function's result type specifies names for its result parameters. The result parameters act as ordinary local variables and the function may assign values to them as necessary. The "return" statement returns the values of these variables.
As for your actual question: the only way to avoid temporary variables would be using non-temporary variables, but usually that would be quite unwise - and probably not much of an optimization even when safe.
So, why doesn't the language specification allow this kind of special use of map indexing (or type assertion or channel receive, both of which can also utilize the "comma ok" idiom) in return statements? That's a good question. My guess: to keep the language specification simple.
I'm no Go expert but I believe you are getting compile time error when you are trying to return the array i.e. return all[id]. The reason could be because the functions return type is specially mentioned as (Info, bool) and when you are doing return all[id] it can't map the return type of all[id] to (Info, bool).
However the solution mentioned above, the variables being returned i and ok are the same that are mentioned in the return type of the function (i Info, ok bool) and hence the compiler knows what it's returning as opposed to just doing (i Info, ok bool).
By default, maps in golang return a single value when accessing a key
https://blog.golang.org/go-maps-in-action
Hence, return all[id] won't compile for a function that expects 2 return values.
I have a table called Employee. Some of the fields in the table are CompanyId, SomeData
I want to query the Min SomeDate based on a companyId.
Something like this:
public DateTime? GetMinDateForCompany(long CompanyId)
{
dataContext.Employees.Where(emp => emp.CompanyID == companyId).Select(emp => emp.SomeDate).Min();
}
If there is no matching companyId, would it throw an exception. Is there a possibility that null could be returned. In general when would nulls be returned for a LINQ-to-SQL query.
You should call the Any() method to make sure you have results. Otherwise, you'll be calling Min() on no results, which will throw an error.
public DateTime GetMinPayrollDateForCompany(long CompanyId)
{
if (dataContext.Payrolls.Any(proll => proll.CompanyID == companyId))
return dataContext.Payrolls.Where(proll => proll.CompanyID == companyId).Select(proll => proll.PayrollDate).Min();
else
return new DateTime();
}
To answer your questions, I do believe that a query that has no results for companyId will throw an error. The Any() method will be your friend. Calling other methods on empty sets will throw errors.
Min will return NULL in SQL. This is expected. The problem arises in C# when you cast the result. if the type is non-nullable, you will get an error like the following:
The null value cannot be assigned to a member with type System.DateTime which is a non-nullable value type.
This is because C# will base the return type on the field you are asking for Min, in this case a DateTime (this is how generics works). But, we can avoid this error by simply typecasting the result to the nullable version of the type!
Your original query would change to the following:
dataContext.Payrolls
.Where(proll => proll.CompanyID == companyId)
.Min(proll => (DateTime?)proll.PayrollDate)
This will give a NULL result instead of throwing an exception. IIRC, if your original type is already nullable, you will not need the typecast.