H2 Oracle decode function - h2
In H2, I have written a Java decode function. It works with the code:
String sql = "select decode(1.0,2.0,3.0,4.0) from dual ;";
PreparedStatement stmt = connection.prepareStatement(sql);
ResultSet resultSet = (ResultSet) stmt.executeQuery();
But the code
String sql = "select 6.0 - decode(1.0,2.0,3.0,4.0) from dual ;";
gives the error:
org.h2.jdbc.JdbcSQLException: Hexadecimal string with odd number of characters: "6.0"; SQL statement:
select 6.0 - decode(1.0,2.0,3.0,4.0) from dual ; [90003-157]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:327)
at org.h2.message.DbException.get(DbException.java:167)
at org.h2.message.DbException.get(DbException.java:144)
at org.h2.util.StringUtils.convertHexToBytes(StringUtils.java:943)
at org.h2.value.Value.convertTo(Value.java:826)
at org.h2.expression.Operation.getValue(Operation.java:108)
at org.h2.command.dml.Select.queryFlat(Select.java:518)
at org.h2.command.dml.Select.queryWithoutCache(Select.java:617)
at org.h2.command.dml.Query.query(Query.java:298)
at org.h2.command.dml.Query.query(Query.java:268)
at org.h2.command.dml.Query.query(Query.java:37)
at org.h2.command.CommandContainer.query(CommandContainer.java:80)
at org.h2.command.Command.executeQuery(Command.java:181)
at org.h2.jdbc.JdbcPreparedStatement.executeQuery(JdbcPreparedStatement.java:96)
My decode function is as:
public final static Value decode(Value expression, Value ... paramValues) {
boolean param = true;
boolean hit = false;
Value returnValue = null;
Value defaultValue = null;
// Walk through all parameters, alternately the 'param' and corresponding 'value'.
// If 'param' is equal the expression, then return the next 'value'.
// If no hit, the return the last 'param' value as default value.
for (Value str : paramValues) {
if (param) {
defaultValue = str; // In case this is the last parameter.
// Remember the hit. The next value will be returned.
hit = (MiscUtil.equals(expression, str));
} else {
if (hit) {
returnValue = str;
break; // return str;
}
defaultValue = null;
}
param = ! param;
}
return (returnValue==null) ? defaultValue : returnValue;
}
Is there anything wrong with my decode function?
I have tried to return Object instead of Value in the decode function, and added this code at the end:
Object returnObject=null;
if (returnValue instanceof ValueDecimal) {
returnObject = ((ValueDecimal)returnValue).getBigDecimal();
} else if (returnValue instanceof ValueString) {
returnObject = ((ValueString)returnValue).getString();
} else if (returnValue instanceof ValueDate) {
returnObject = ((ValueDate)returnValue).getDate();
}
return returnValue;
But the I got:
org.h2.jdbc.JdbcSQLException: Data conversion error converting "aced0005737200146a6176612e6d6174682e426967446563696d616c54c71557f981284f0300024900057363616c654c0006696e7456616c7400164c6a6176612f6d6174682f426967496e74656765723b787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000001737200146a6176612e6d6174682e426967496e74656765728cfc9f1fa93bfb1d030006490008626974436f756e744900096269744c656e67746849001366697273744e6f6e7a65726f427974654e756d49000c6c6f776573745365744269744900067369676e756d5b00096d61676e69747564657400025b427871007e0002fffffffffffffffffffffffefffffffe00000001757200025b42acf317f8060854e0020000787000000001287878"; SQL statement:
select 6.0 - cast(decode(1.0,2.0,3.0,4.0) as double) xxx from dual ; [22018-157]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:327)
at org.h2.message.DbException.get(DbException.java:156)
at org.h2.value.Value.convertTo(Value.java:855)
at org.h2.expression.Function.getSimpleValue(Function.java:733)
at org.h2.expression.Function.getValueWithArgs(Function.java:893)
at org.h2.expression.Function.getValue(Function.java:432)
at org.h2.expression.Operation.getValue(Operation.java:113)
at org.h2.expression.Alias.getValue(Alias.java:35)
...
I also did some try with ValueExpression without luck.
Full support for decode in H2 would be the best solution. Is that something you can provide Thomas?
H2 thinks the data type is JAVA_OBJECT, and therefore wants to convert the parameters (6.0 and the result of the decode) to JAVA_OBJECT, which means first convert to a byte array. This fails.
I didn't test it myself, but explicit CAST should work:
select 6.0 - cast(decode(1.0,2.0,3.0,4.0) as double) from dual
It's a bit ugly I know.
Related
Blazor .net core ref enum? param not changing its value
Im a bit confused with whats happening bellow: Can anyone explain me why is dataType keep saying StatisticData instead of SibsMonthly?? dataType is a enum? passad as ref param to this method and its initialized as null before the method call.. Here is the code: string errorMessage = null; Enums.Uploads.DataType? dataType = null; if (ValidadeFile(file, ref errorMessage, ref dataType)) { ... } private bool ValidadeFile(IBrowserFile file, ref string errorMessage, ref Enums.Uploads.DataType? dataType) { List<string> acceptedFileTypes = new List<string> { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }; var valid = true; if (AcceptedFileNames != null && AcceptedFileNames.Length > 0) { var tmp = AcceptedFileNames.Where(x => new Regex(x.Regex).IsMatch(file.Name)) .OrderByDescending(x => x.DataType) .Select(x => x.DataType) .FirstOrDefault(); dataType = tmp; if (dataType == null) { valid = false; errorMessage = Constants.Uploads.Error.InvalidFileName; } } ... }
The WASM debugger doesn't seem to like ref variables, it seems to look at their address, not their value: Inspecting them at their call site or in the Debug window behaves as expected; this is a debugger isssue.
SonarQube nonconstant String in SQL statements
I'm scanning my code with SonarQube and I'm getting the following bugs: -A prepared statement is generated from a nonconstant String -Nonconstant string passed to execute method on an SQL statement I have an sql query to which I append based on some conditions. Example: PreparedStatement ps = null; StringBuilder sql = new StringBuilder("UPDATE" + tableName + " SET some_field = ? WHERE a_field = a_value"); if (myObject.getField1() != null) { sql.append(" AND Field1 = " + myObject.getField1()); } if (myObject.getField2() != null) { sql.append(" AND Field2 = " + myObject.getField2()); } if (myObject.getField3() != null) { sql.append(" AND Field3 = " + myObject.getField3()); } if (myObject.getField4() != null) { sql.append(" AND Field4 = " + myObject.getField4()); } ... **ps = connection.prepareStatement(sql.toString());** //generating bug if (myObject.getSomeField() == null) { ps.setNull(1, nevermind); } else { ps.setString(1, myObject.getSomeField()); } I tried passing a final String = sql.toString(); to the prepareStatement() function and it still generates the bug.
The issue that's being raised is that you're assembling your SQL command with concatenation: which table to update, which columns to set and what values to put in them. You should find a way to hard code the table and columns and use parameter binding for the values.
How to return DateTimeOffset type with Linq
how to return DateTimeOffset with a Linq query. I need to get a due date from a table of type DateTimeOffset public DateTimeOffset GetLastDate(Guid Id, Guid AppId) { var q = from k in context.Inspections where k.Id == Id || k.AppId == AppId select k.Duedate; return q; } cannot implicitly convert system.Linq.IQueryable to System.DateTimeOffset
The problem is that your query will return an IQueryable<T>, with the type being the type of Duedate. If Duedate is a DateTimeOffset, you could return the first result (Where can return multiple matches) via: var q = from k in context.Inspections where k.Id== Id||k.AppId== AppId select k.Duedate; DateTimeOffset? value = q.First(); if (value.HasValue) return value.Value; else // found NULL in DB! Do something in this case... throw new ApplicationException("Null offset found"); // Alternatively, you could use some default value (this uses "Now"): // return value ?? DateTimeOffset.Now;
How to get out of repetitive if statements?
While looking though some code of the project I'm working on, I've come across a pretty hefty method which does the following: public string DataField(int id, string fieldName) { var data = _dataRepository.Find(id); if (data != null) { if (data.A == null) { data.A = fieldName; _dataRepository.InsertOrUpdate(data); return "A"; } if (data.B == null) { data.B = fieldName; _dataRepository.InsertOrUpdate(data); return "B"; } // keep going data.C through data.Z doing the exact same code } } Obviously having 26 if statements just to determine if a property is null and then to update that property and do a database call is probably very naive in implementation. What would be a better way of doing this unit of work?
Thankfully C# is able to inspect and assign class members dynamically, so one option would be to create a map list and iterate over that. public string DataField(int id, string fieldName) { var data = _dataRepository.Find(id); List<string> props = new List<string>(); props.Add("A"); props.Add("B"); props.Add("C"); if (data != null) { Type t = typeof(data).GetType(); foreach (String entry in props) { PropertyInfo pi = t.GetProperty(entry); if (pi.GetValue(data) == null) { pi.SetValue(data, fieldName); _dataRepository.InsertOrUpdate(data); return entry; } } } }
You could just loop through all the character from 'A' to 'Z'. It gets difficult because you want to access an attribute of your 'data' object with the corresponding name, but that should (as far as I know) be possible through the C# reflection functionality. While you get rid of the consecutive if-statements this still won't make your code nice :P
there is a fancy linq solution for your problem using reflection: but as it was said before: your datastructure is not very well thought through public String DataField(int id, string fieldName) { var data = new { Z = "test", B="asd"}; Type p = data.GetType(); var value = (from System.Reflection.PropertyInfo fi in p.GetProperties().OrderBy((fi) => fi.Name) where fi.Name.Length == 1 && fi.GetValue(data, null) != null select fi.Name).FirstOrDefault(); return value; } ta taaaaaaaaa like that you get the property but the update is not yet done.
var data = _dataRepository.Find(id); If possible, you should use another DataType without those 26 properties. That new DataType should have 1 property and the Find method should return an instance of that new DataType; then, you could get rid of the 26 if in a more natural way. To return "A", "B" ... "Z", you could use this: return (char)65; //In this example this si an "A" And work with some transformation from data.Value to a number between 65 and 90 (A to Z).
Since you always set the lowest alphabet field first and return, you can use an additional field in your class that tracks the first available field. For example, this can be an integer lowest_alphabet_unset and you'd update it whenever you set data.{X}: Init: lowest_alphabet_unset = 0; In DataField: lowest_alphabet_unset ++; switch (lowest_alphabet_unset) { case 1: /* A is free */ /* do something */ return 'A'; [...] case 7: /* A through F taken */ data.G = fieldName; _dataRepository.InsertOrUpdate(data); return 'G'; [...] }
N.B. -- do not use, if data is object rather that structure. what comes to my mind is that, if A-Z are all same type, then you could theoretically access memory directly to check for non null values. start = &data; for (i = 0; i < 26; i++){ if ((typeof_elem) *(start + sizeof(elem)*i) != null){ *(start + sizeof(elem)*i) = fieldName; return (char) (65 + i); } } not tested but to give an idea ;)
How to convert a string to decimal in a LINQ query
I have the following Linq statement: var total = (from a in mobileChunk.Data select a.callCost).Sum(); callCost is a string. I need to convert it to a decimal. How is this done?
i would do something like this.... public static class Extenders { public static decimal ToDecimal(this string str) { // you can throw an exception or return a default value here if ( string.IsNullOrEmpty(str) ) return someDefaultValue; decimal d ; // you could throw an exception or return a default value on failure if ( !decimal.TryParse(str, out d ) ) return someDefaultValue; return d; } } now, in your linq..... var total = = (from a in mobileChunk.Data select a.callCost.ToDecimal()).Sum();
Perhaps you can try this: var total = (from a in mobileChunk.Data select decimal.Parse(a.callCost)).Sum();