groovy insert statement Can't infer the SQL type to use for an instance of org.codehaus.groovy.runtime.GStringImpl - sql

error message:
URI
/racetrack/readUserRole/index
Class
org.postgresql.util.PSQLException
Message
Can't infer the SQL type to use for an instance of org.codehaus.groovy.runtime.GStringImpl. Use setObject() with an explicit Types value to specify the type to use
code:
a="col01"
b="col${usercol}"
c="col${rolecol}"
sql.eachRow("select $a,$b,$c from read_csv where col01=? and col${usercol}!=? ", [file.name,""]) {
t="${it."$a"}"
i="${it."$b"}"
r="${it."$c"}"
t.getClass() == String
i.getClass()== String
r.getClass()== String
def list2=[t,i,r]
println list2
sql.execute('insert into read_user_role(version,roledata,textname,userdata)'+
'VALUES (0,?,?,?)', list2)
}
the problem occurred at insert statement as error message, so how i suppose to fix this sql type issue?

Use the static methods on the Sql class to wrap your variable into a type known to the database. For example, to wrap a GString as varchar, you can use:
import static groovy.sql.Sql.*
....
sql.eachRow("select * from foo where name = ${VARCHAR(myVar)}")

Related

Scala Spark: Parse SQL string to Column

I have two functions, foo and bar, that I want to write like follows:
def foo(df : DataFrame, conditionString : String) =
val conditionColumn : Column = something(conditionString) //help me define "something"
bar(df, conditionColumn)
}
def bar(df : DataFrame, conditionColumn : Column) = {
df.where(conditionColumn)
}
Where condition is a sql string like "person.age >= 18 AND person.citizen == true" or something.
Because reasons, I don't want to change the type signatures here. I feel this should work because if I could change the type signatures, I could just write:
def foobar(df : DataFrame, conditionString : String) = {
df.where(conditionString)
}
As .where is happy to accept a sql string expression.
So, how can I turn a string representing a column expression into a column? If the expression were just the name of a single column in df I could just do col(colName), but that doesn't seem to take the range of expressions that .where does.
If you need more context for why I'm doing this, I'm working on a databricks notebook that can only accept string arguments (and needs to take a condition as an argument), which calls a library I want to take column-typed arguments.
You can use functions.expr:
def expr(expr: String): Column
Parses the expression string into the column that it represents

unable to print multiple Boolean in Kotlin

i'm beginning with kotlin language
fun main (args:Array<String>){
var flag1:Boolean= true //Explicit declaration
var flag2: =false //Implicit declaration
println(flag2 + "and " + flag1)
println(flag1)
println(flag2)
}
in above code i have declared 2 type of boolean Explicit and Implicit declaration
for above code i would say expect following ouput :-
false and true
true
false
but i'm getting following erroe :-
can anyone explain where did i go wrong ?
For that compiler error, change this:
println(flag2 + "and " + flag1)
to this:
println("$flag2 and $flag1")
Kotlin is strongly typed language and you can't use plus operator on String and Boolean types.
But you can use string interpolation, with $ operator inside a string literal.
You could also make it compile with overloaded plus operator on the Boolean type by adding this:
operator fun Boolean.plus(s: String): String {
return this.toString() + s
}
In Java, it performs string conversion when you concatenate a string with any type of object. For example,
System.out.println(true + " and false"); //Output: true and false
In Kotlin, string conversion doesn't exist. Alternatively, you may use string templates for that.
println("$flag2 and $flag1")
Besides, since Kotlin's String class provide plus(Any?) function which receives any type as parameter, so the following line of code is still valid:
println("$flag2 and " + flag1)
Here is a discussion on this design.

Bind nulls into prepared statement

I have this code:
String updText = "update table set varcharPar=?, floatPar=?, datePar=?, intPar=? where id=7"
def updateCounts = sql.withBatch(1, updText) { ps ->
def args = [Types.NULL, Types.NULL, Types.NULL, Types.NULL]
ps.addBatch(args)
}
And when I try to update it doesn't work with varchar parameter, gives me
Caught: java.sql.BatchUpdateException: Implicit conversion
from datatype 'INT' to 'VARCHAR' is not allowed.
Use the CONVERT function to run this query.
It works on int, float and dates. How can I solve this?
If I put null instead of Types.NULL it doesn't work with float.

Call SQL stored procedure with named parameter in Groovy

private static String XXX = "{call SP_XXX(?,?,?)}"
sql.call (XXX, [Sql.NUMERIC, Sql.NUMERIC,'SOME STRING'){
outPara1, outPara2 ->
log.info("${outPara1}, ${outPara2}")
}
I am able to call the stored procedure successful with the above code.
But, when I am using named parameters instead of '?' placeholder.
I am getting:
WARNING: Failed to execute: {call SP_XXX(:OUTP1, :OUTP2, :INP1)}
because: Invalid column type
What I changed is replaced the '?' with ":OUTP1", "OUTP2" and ":INP1".
And in the call statement, using the named parameters accordingly.
The code after change:
private static String XXX = "{call SP_XXX(:OUTP1, :OUTP2, :INP1)}"
sql.call (XXX, [OUTP1: Sql.NUMERIC, OUTP2: Sql.NUMERIC, INP1: 'SOME STRING']){
outPara1, outPara2 ->
log.info("${outPara1}, ${outPara2}")
}
What you are doing is passing a map to call() which I do not think we have an api for. Moreover, the placeholders for the SP has to be ?.
Either you can stick to your former approach or try using GString as below:
def inp1 = 'SOME STRING'
sql.call "{call SP_XXX(${Sql.NUMERIC}, ${Sql.NUMERIC}, $inp1)}", {
outPara1, outPara2 ->
log.info("${outPara1}, ${outPara2}")
}
I would prefer the former approach instead. :-)

Powershell and SQL parameters. If empty string, pass DBNull

I got this parameter:
$objDbCmd.Parameters.Add("#telephone", [System.Data.SqlDbType]::VarChar, 18) | Out-Null;
$objDbCmd.Parameters["#telephone"].Value = $objUser.Telephone;
Where the string $objUser.Telephone can be empty. If it's empty, how can I convert it to [DBNull]::Value?
I tried:
if ([string]:IsNullOrEmpty($objUser.Telephone)) { $objUser.Telephone = [DBNull]::Value };
But that gives me the error:
Exception calling "ExecuteNonQuery" with "0" argument(s): "Failed to convert parameter value from a ResultPropertyValueCollection to a String."
And if I convert it to a string, it inserts an empty string "", and not DBNull.
How can this be accomplished?
Thanks.
In PowerShell, you can treat null/empty strings as a boolean.
$x = $null
if ($x) { 'this wont print' }
$x = ""
if ($x) { 'this wont print' }
$x = "blah"
if ($x) { 'this will' }
So.... having said that you can do:
$Parameter.Value = $(if ($x) { $x } else { [DBNull]::Value })
But I'd much rather wrap this up in a function like:
function CatchNull([String]$x) {
if ($x) { $x } else { [DBNull]::Value }
}
I don't know about powershell, but in C# I would do something like this:
if ([string]::IsNullOrEmpty($objUser.Telephone))
{
$objDbCmd.Parameters["#telephone"].Value = [DBNull]::Value;
}
else
{
$objDbCmd.Parameters["#telephone"].Value = $objUser.Telephone;
}
Always append +"" at the end of db values...
$command.Parameters["#EmployeeType"].Value= $ADResult.EmployeeType + ""
Many years later, let me clarify:
Josh's answer shows a helpful simplification for testing strings for emptiness (relying on PowerShell's implicit to-Boolean conversion[1]), but it is unrelated to Tommy's (the OP's) problem.
Instead, the error message
"Failed to convert parameter value from a ResultPropertyValueCollection to a String."
implies that it is the non-null case that caused the problem, because $objDbCmd.Parameters["#telephone"].Value expects either a string value or [DBNull]::Value, whereas $objUser.Telephone is of type [ResultPropertyValueCollection], i.e. a collection of values.
Thus, in the non-null case, a string value must be assigned, which must be derived from the collection; one option is to take the first collection element's value, another would be to join all values with a separator to form a single string, using, e.g., [string]::Join(';', $objUser.Telephone) or, if joining the elements with spaces is acceptable (not a good idea with multiple phone numbers), simply with "$($objUser.Telephone)".[2]
Detecting an empty collection via [string]:IsNullOrEmpty() actually worked, despite the type mismatch, due to how PowerShell implicitly stringifies collections when passing a value to a [string] typed method parameter.[2]
Similarly, using implicit to-Boolean conversion works as expected with collections too: an empty collection evaluates to $false, a non-empty one to $true (as long as there are either at least two elements or the only element by itself would be considered $true[1])
Therefore, one solution is to use the first telephone number entry:
$objDbCmd.Parameters["#telephone"].Value = if ($objUser.Telephone) {
$objUser.Telephone[0].ToString() # use first entry
} else {
[DBNull]::Value
}
Note: If $objUser.Telephone[0] directly returns a [string], you can omit the .ToString() call.
In PowerShell v7+ you can alternatively shorten the statement via a ternary conditional:
$objDbCmd.Parameters["#telephone"].Value =
$objUser.Telephone ? $objUser.Telephone[0].ToString() : [DBNull]::Value
[1] For a comprehensive summary of PowerShell's automatic to-Boolean conversions, see the bottom section of this answer.
[2] When implicitly converting a collection to a string, PowerShell joins the stringified elements of a collection with a single space as the separator by default; you can override the separator with the automatic $OFS variable, but that is rarely done in practice; e.g., array 'foo', 'bar' is converted to 'foo bar'; note that this conversion does not apply when you call the collection's .ToString() method explicitly, but it does apply inside expandable (interpolating) strings, e.g., "$array".