Ok it makes more sense to me now, conversion needs to take place at a level where the relevant information is still available so doing it on a low level isn't really an option (even though that's been allowed to happen up until now). I guess I was having trouble understanding why we needed to do all this work when everything had been running fine, but I see now that it wasn't really running that fine.
Thanks Scott 2008/10/15 Adrian Crum <[EMAIL PROTECTED]>: > In addition, the service event handler has the information needed to perform > a proper conversion (locale and time zone). The entity engine does not. > > -Adrian > > David E Jones wrote: >> >> I wouldn't say that bugs would be "created" by this change, more than >> existing bugs would be exposed (that are only visible on certain databases, >> etc). >> >> The service engine doesn't actually do automated mapping, is the service >> event handler that does this for web requests before the actual call to the >> service engine. In fact when a service is called through the service engine >> it will return an error if the object types of values passed in don't match >> what is in the service definition. The difference is that it was that way >> from the beginning, which isn't the case with certain parts of the entity >> engine (mainly in order to not cause the problem of exposing bugs that were >> dormant most of the time... which isn't really good in my current opinion). >> >> -David >> >> >> On Oct 14, 2008, at 2:09 AM, Scott Gray wrote: >> >>> Ok I see your point, thanks for explaining. >>> >>> #1 makes sense but it will be interesting to see how many bugs are >>> created, also doesn't the service engine currently perform automatic >>> conversion without any problems? >>> >>> Regards >>> Scott >>> >>> 2008/10/14 David E Jones <[EMAIL PROTECTED]>: >>>> >>>> On Oct 13, 2008, at 10:10 PM, Scott Gray wrote: >>>> >>>>> Inline: >>>>> >>>>> 2008/10/14 David E Jones <[EMAIL PROTECTED]>: >>>>>> >>>>>> Scott, are you referring to the call to PreparedStatement.setString on >>>>>> SQLProcessor line 553? In other words, the difference in the Postgres >>>>>> JDBC >>>>>> driver is that they used to auto-convert from a String to whatever the >>>>>> database needs in the setString method, but now they don't? >>>>> >>>>> When we call PreparedStatement.setString() the JDBC driver now adds >>>>> something like String:varchar to the parameter list where it used to >>>>> add String:unspecified which meant the database would try and take >>>>> care of it, but with varchar it just says "wrong!" and throws an >>>>> error. However if we call PreparedStatement.setObject() passing in >>>>> the correct sql type then we get String:timestamp and everything works >>>>> fine. >>>>> >>>>> So I guess what I'm saying is that I think java type conversion >>>>> (String vs Timestamp) is a separate topic and the problem here is >>>>> simply the sql type that we are specifying (by calling the various >>>>> PreparedStatement methods) does not match the column type. We could >>>>> probably solve the postgresql issue by simply calling >>>>> setObject(Types.OTHER) whenever the value type doesn't match entity >>>>> field type. >>>> >>>> The real problem is we're passing bad data back to the database and >>>> expecting it to deal with it. Right now the entity engine is just >>>> warning >>>> about such problems in the log, allowing them to go back to the JDBC >>>> driver >>>> and/or database where they become a real problem. >>>> >>>> If we do something like always call setObject then chances are good >>>> we'll >>>> have problems with other databases. If I remember right we used to do >>>> that >>>> generically and it caused problems and we had to move to the current >>>> approach of using object time specific methods. >>>> >>>>>> What I'm proposing is to fix this further up the stack in the >>>>>> GenericEntity.set method instead of lower down. >>>>> >>>>> That's fine for when we are using the GenericEntity but we'd also need >>>>> to add similar code to the EntityCondition stuff for find queries >>>>> (which is where Jacques noticed the problem, I haven't checked for the >>>>> error on any operations involving GenericEntity). >>>> >>>> Good point, we'll have to make sure the object types passed into those >>>> are >>>> valid as well. >>>> >>>> -David >>>> >>>> >>>> >>>>>> On Oct 13, 2008, at 7:14 PM, Scott Gray wrote: >>>>>> >>>>>>> Here's the problem as I see it: >>>>>>> Postgresql used to allow you to specify parameter types which did not >>>>>>> match the column type, in the timestamp case if you passed in a >>>>>>> parameter specified as varchar it would automatically attempt to >>>>>>> convert it to a timestamp. Now Postgresql requires that you either >>>>>>> pass in the correct parameter type for the column or otherwise pass >>>>>>> the parameter type as unknown/unspecified. Postgresql still doesn't >>>>>>> care whether you pass in a string or a timestamp but you MUST specify >>>>>>> the correct sql type. >>>>>>> >>>>>>> If letting the database take care of the type conversion has never >>>>>>> been a problem before, why do we need to worry about it now? >>>>>>> Remember >>>>>>> the only problem here is that we are passing in a string specified as >>>>>>> varchar instead of a string specified as java.sql.Types.Timestamp. >>>>>>> >>>>>>> Regards >>>>>>> Scott >>>>>>> >>>>>>> 2008/10/14 Adrian Crum <[EMAIL PROTECTED]>: >>>>>>>> >>>>>>>> I understood your alternatives. I apologize for being unclear. >>>>>>>> >>>>>>>> You said, "or to just throw an exception when the wrong data type is >>>>>>>> passed >>>>>>>> like the commented out code in GenericEntity referenced above does." >>>>>>>> >>>>>>>> And I'm saying we could do that, but it's going to get interesting >>>>>>>> because a >>>>>>>> lot of code passes Strings into the entity engine. In other words, >>>>>>>> if >>>>>>>> we >>>>>>>> throw a "hard" exception, there is a good chance that much of OFBiz >>>>>>>> won't >>>>>>>> run. >>>>>>>> >>>>>>>> Personally, I'd like to see better handling of object types in the >>>>>>>> higher >>>>>>>> level code. I fixed a problem over the weekend that was caused by >>>>>>>> this >>>>>>>> very >>>>>>>> thing (passing Strings into the entity engine). >>>>>>>> >>>>>>>> -Adrian >>>>>>>> >>>>>>>> >>>>>>>> David E Jones wrote: >>>>>>>>> >>>>>>>>> I'm referring to the exception I described in the >>>>>>>>> GenericEntity.java >>>>>>>>> file, >>>>>>>>> lines 410-415. Right now it is just a warning in the log (and has >>>>>>>>> been >>>>>>>>> for >>>>>>>>> years). The reason to do it there instead of letting the JDBC >>>>>>>>> driver >>>>>>>>> do >>>>>>>>> it >>>>>>>>> is that not all developers will test on all possible databases, and >>>>>>>>> this >>>>>>>>> will help avoid errors as people use different databases in >>>>>>>>> development/testing or deployment. >>>>>>>>> >>>>>>>>> I tried to describe two possible approaches to improve this >>>>>>>>> situation >>>>>>>>> in >>>>>>>>> my first message. Please let me know if those alternatives were not >>>>>>>>> clear >>>>>>>>> and I'll try to explain them better. >>>>>>>>> >>>>>>>>> -David >>>>>>>>> >>>>>>>>> >>>>>>>>> On Oct 13, 2008, at 5:22 PM, Adrian Crum wrote: >>>>>>>>> >>>>>>>>>> Wasn't that being done already? Jacques started these changes >>>>>>>>>> based >>>>>>>>>> on >>>>>>>>>> exceptions being thrown by his JDBC driver. Other DBs seemed to be >>>>>>>>>> working >>>>>>>>>> okay. >>>>>>>>>> >>>>>>>>>> I guess we could throw our own exception to keep things consistent >>>>>>>>>> across >>>>>>>>>> databases. It will be interesting to see how that affects existing >>>>>>>>>> code. >>>>>>>>>> >>>>>>>>>> -Adrian >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> David E Jones wrote: >>>>>>>>>>> >>>>>>>>>>> That is a very good point, and I agree. >>>>>>>>>>> To me that means we go with the fail-fast approach and have it >>>>>>>>>>> throw >>>>>>>>>>> an >>>>>>>>>>> exception if you pass in something that is not the correct object >>>>>>>>>>> type. >>>>>>>>>>> Is that what you meant? >>>>>>>>>>> -David >>>>>>>>>>> On Oct 13, 2008, at 4:57 PM, Adrian Crum wrote: >>>>>>>>>>>> >>>>>>>>>>>> I would prefer handling object types in higher level code - due >>>>>>>>>>>> to >>>>>>>>>>>> ambiguity in how some types would be converted from a String >>>>>>>>>>>> (currency, >>>>>>>>>>>> date, time, etc). >>>>>>>>>>>> >>>>>>>>>>>> -Adrian >>>>>>>>>>>> >>>>>>>>>>>> David E Jones wrote: >>>>>>>>>>>>> >>>>>>>>>>>>> This has been a potential problem for a while, but the decision >>>>>>>>>>>>> was >>>>>>>>>>>>> made quite a while back to not enforce the correct object type. >>>>>>>>>>>>> There is code in the GenericEntity.java file (lines 410-415) to >>>>>>>>>>>>> check >>>>>>>>>>>>> to see if the value passed in matches the object type for the >>>>>>>>>>>>> field >>>>>>>>>>>>> it is >>>>>>>>>>>>> being set on. >>>>>>>>>>>>> The best way to solve this problem is a good question. It might >>>>>>>>>>>>> be >>>>>>>>>>>>> good to introduce some automatic type conversion, or to just >>>>>>>>>>>>> throw >>>>>>>>>>>>> an >>>>>>>>>>>>> exception when the wrong data type is passed like the commented >>>>>>>>>>>>> out >>>>>>>>>>>>> code in >>>>>>>>>>>>> GenericEntity referenced above does. >>>>>>>>>>>>> The most common form of automatic conversion is from String to >>>>>>>>>>>>> whatever the field's object type is, and that is done by the >>>>>>>>>>>>> GenericEntity.setString method. >>>>>>>>>>>>> So, what do people think about this? Should we do an automatic >>>>>>>>>>>>> type >>>>>>>>>>>>> conversion to try to fix programming errors automatically, or >>>>>>>>>>>>> do a >>>>>>>>>>>>> fail-fast >>>>>>>>>>>>> by throwing an exception when the object type is wrong? I >>>>>>>>>>>>> suppose >>>>>>>>>>>>> the >>>>>>>>>>>>> current fail-quiet (in the log) and fail loudly on certain >>>>>>>>>>>>> databases >>>>>>>>>>>>> later >>>>>>>>>>>>> is not the best option... >>>>>>>>>>>>> -David >>>>>>>>>>>>> On Oct 12, 2008, at 2:20 PM, Scott Gray wrote: >>>>>>>>>>>>>> >>>>>>>>>>>>>> I've had a look into this and I can't see anything related to >>>>>>>>>>>>>> Groovy >>>>>>>>>>>>>> that is making this necessary, it appears to be entirely a >>>>>>>>>>>>>> postgresql >>>>>>>>>>>>>> issue. >>>>>>>>>>>>>> >>>>>>>>>>>>>> When executing a prepared statement postgresql seems to >>>>>>>>>>>>>> require >>>>>>>>>>>>>> that >>>>>>>>>>>>>> the parameter list sql types match the column types. So the >>>>>>>>>>>>>> problem >>>>>>>>>>>>>> isn't that we are passing in a string but that we are setting >>>>>>>>>>>>>> the >>>>>>>>>>>>>> sql >>>>>>>>>>>>>> type to character varying by using >>>>>>>>>>>>>> PreparedStatement.setString(). >>>>>>>>>>>>>> >>>>>>>>>>>>>> Here's a patch that fixes the issue but I'm not really >>>>>>>>>>>>>> confident >>>>>>>>>>>>>> enough to commit it, it would be great to get some comments >>>>>>>>>>>>>> from >>>>>>>>>>>>>> people who know more about this kind of thing: >>>>>>>>>>>>>> >>>>>>>>>>>>>> Index: >>>>>>>>>>>>>> framework/entity/src/org/ofbiz/entity/jdbc/SQLProcessor.java >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> =================================================================== >>>>>>>>>>>>>> --- >>>>>>>>>>>>>> framework/entity/src/org/ofbiz/entity/jdbc/SQLProcessor.java >>>>>>>>>>>>>> (revision >>>>>>>>>>>>>> 703572) >>>>>>>>>>>>>> +++ >>>>>>>>>>>>>> framework/entity/src/org/ofbiz/entity/jdbc/SQLProcessor.java >>>>>>>>>>>>>> (working copy) >>>>>>>>>>>>>> @@ -592,6 +592,22 @@ >>>>>>>>>>>>>> * >>>>>>>>>>>>>> * @throws SQLException >>>>>>>>>>>>>> */ >>>>>>>>>>>>>> + public void setValueTimestampString(String field) throws >>>>>>>>>>>>>> SQLException { >>>>>>>>>>>>>> + if (field != null) { >>>>>>>>>>>>>> + _ps.setObject(_ind, field, Types.TIMESTAMP); >>>>>>>>>>>>>> + } else { >>>>>>>>>>>>>> + _ps.setNull(_ind, Types.TIMESTAMP); >>>>>>>>>>>>>> + } >>>>>>>>>>>>>> + _ind++; >>>>>>>>>>>>>> + } >>>>>>>>>>>>>> + >>>>>>>>>>>>>> + /** >>>>>>>>>>>>>> + * Set the next binding variable of the currently active >>>>>>>>>>>>>> prepared >>>>>>>>>>>>>> statement. >>>>>>>>>>>>>> + * >>>>>>>>>>>>>> + * @param field >>>>>>>>>>>>>> + * >>>>>>>>>>>>>> + * @throws SQLException >>>>>>>>>>>>>> + */ >>>>>>>>>>>>>> public void setValue(java.sql.Time field) throws SQLException >>>>>>>>>>>>>> { >>>>>>>>>>>>>> if (field != null) { >>>>>>>>>>>>>> _ps.setTime(_ind, field); >>>>>>>>>>>>>> Index: >>>>>>>>>>>>>> framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> =================================================================== >>>>>>>>>>>>>> --- >>>>>>>>>>>>>> framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java >>>>>>>>>>>>>> (revision >>>>>>>>>>>>>> 703572) >>>>>>>>>>>>>> +++ >>>>>>>>>>>>>> framework/entity/src/org/ofbiz/entity/jdbc/SqlJdbcUtil.java >>>>>>>>>>>>>> (working copy) >>>>>>>>>>>>>> @@ -731,6 +731,9 @@ >>>>>>>>>>>>>> fieldClassName = "byte[]"; >>>>>>>>>>>>>> } >>>>>>>>>>>>>> >>>>>>>>>>>>>> + if ("java.sql.Timestamp".equals(fieldType)) { >>>>>>>>>>>>>> + fieldClassName = fieldType; >>>>>>>>>>>>>> + } >>>>>>>>>>>>>> if (Debug.verboseOn()) Debug.logVerbose("type of >>>>>>>>>>>>>> field " + entityName + "." + modelField.getName() + >>>>>>>>>>>>>> " is " + fieldClassName + ", was expecting " >>>>>>>>>>>>>> + mft.getJavaType() + "; this may " + >>>>>>>>>>>>>> "indicate an error in the configuration or in >>>>>>>>>>>>>> the class, and may result " + >>>>>>>>>>>>>> @@ -749,7 +752,11 @@ >>>>>>>>>>>>>> break; >>>>>>>>>>>>>> >>>>>>>>>>>>>> case 2: >>>>>>>>>>>>>> - sqlP.setValue((java.sql.Timestamp) >>>>>>>>>>>>>> fieldValue); >>>>>>>>>>>>>> + if (fieldValue instanceof String) { >>>>>>>>>>>>>> + sqlP.setValueTimestampString((String) >>>>>>>>>>>>>> fieldValue); >>>>>>>>>>>>>> + } else { >>>>>>>>>>>>>> + sqlP.setValue((java.sql.Timestamp) >>>>>>>>>>>>>> fieldValue); >>>>>>>>>>>>>> + } >>>>>>>>>>>>>> break; >>>>>>>>>>>>>> >>>>>>>>>>>>>> case 3: >>>>>>>>>>>>>> >>>>>>>>>>>>>> Regards >>>>>>>>>>>>>> Scott >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> 2008/10/13 Jacques Le Roux <[EMAIL PROTECTED]>: >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> Done in revision: 703816 >>>>>>>>>>>>>>> It was not possible for PackingSlip.groovy and >>>>>>>>>>>>>>> FindInventoryEventPlan.groovy. Because there the date string >>>>>>>>>>>>>>> is >>>>>>>>>>>>>>> build >>>>>>>>>>>>>>> dynamically in the Groovy file >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> Jacques >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> From: "Jacques Le Roux" <[EMAIL PROTECTED]> >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> Adrian, >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> Yes good idea indeed, I will do that >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> Jacques >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> From: "Adrian Crum" <[EMAIL PROTECTED]> >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> Jacques, >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> Instead of modifying the groovy files, try specifying the >>>>>>>>>>>>>>>>> data >>>>>>>>>>>>>>>>> type in >>>>>>>>>>>>>>>>> the screen widget. >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> Example in ReportFinancialSummaryScreens.xml: >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> <set field="fromDate" from-field="parameters.fromDate" >>>>>>>>>>>>>>>>> type="Timestamp"/> >>>>>>>>>>>>>>>>> <set field="thruDate" from-field="parameters.thruDate" >>>>>>>>>>>>>>>>> type="Timestamp"/> >>>>>>>>>>>>>>>>> <script >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> location="component://accounting/webapp/accounting/WEB-INF/actions/reports/TransactionTotals.groovy"/> >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> -Adrian >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>> >>>>>> >>>> >>>> >> >> >