B4J Question ResultSet MetaData Oracle

XbNnX_507

Active Member
Licensed User
Longtime User
Hi, i'm getting an extrange error here.
B4X:
    CallableStatement.RunMethod("registerOutParameter", Array( CursorIndex, OracleTypes.GetField("CURSOR")) )
    CallableStatement.RunMethod("execute", Null) 
    Dim rs As ResultSet = CallableStatement.RunMethod("getCursor", Array(CursorIndex)) '
    Dim jrs As JavaObject = rs
    Dim rsmd As JavaObject = jrs.RunMethod("getMetaData", Null)   ' <- error here

B4X:
Waiting for debugger to connect...
Program started.
Error occurred on line: 61 (Main)
java.lang.RuntimeException: Method: getMetaData not found in: oracle.jdbc.driver.ForwardOnlyResultSet
    at anywheresoftware.b4j.object.JavaObject$MethodCache.getMethod(JavaObject.java:363)
    at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:120)
    at b4j.example.main._procedurequery(main.java:194)
    at b4j.example.main._appstart(main.java:111)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:632)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:237)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:91)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:98)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:78)
    at b4j.example.main.start(main.java:38)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$166(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$179(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$177(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$178(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$152(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)
Isn't this method supposed to return the resulset metadata?
 

DonManfred

Expert
Licensed User
Longtime User
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Looks like the standard prepareCall method that the SQL library is using will only return a ForwardOnlyResultSet. That object's interface is limited (other methods do not work, but with a different error messsage). There is another prepareCall method whose signature is
CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
Where resultSetType can be
ResultSet.TYPE_FORWARD_ONLY
ResultSet.TYPE_SCROLL_INSENSITIVE
or ResultSet.TYPE_SCROLL_SENSITIVE
and sesultSetConcurrency can be
ResultSet.CONCUR_READ_ONLY
or ResultSet.CONCUR_UPDATABLE
For the standard prepareCall, the resultSetType is ResultSet.TYPE_FORWARD_ONLY and resultSetConcurrency is ResultSet.CONCUR_READ_ONLY. You'll need to do your own prepareCall with resultSetType set to either ResultSet.TYPE_SCROLL_INSENSITIVE or ResultSet.TYPE_SCROLL_SENSITIVE. In order to do you own call, you'll need to get a hold of the connection object of the SQL object.

Edit: Forgot sources and looks like there are some limitations that you may run into when using the prepareCall mentioned above.
Sources:
Limitations of ForwardOnlyResultSet:
https://www.javamadesoeasy.com/2015/12/solve-javasqlsqlexception-invalid.html
https://coderanch.com/t/487347/databases/Invalid-operation-resultset-beforeFirst
Info on prepareCall:
https://docs.oracle.com/cd/A97335_02/apps.102/a83724/resltse2.htm
Please read "Result Set Limitations and Downgrade Rules" section!
 
Last edited:
Upvote 0

XbNnX_507

Active Member
Licensed User
Longtime User
Well after trying everything with my little to non existent java knowledge
( that's why i use b4j lol )...
i did this...
B4X:
Dim JO As JavaObject = Me
Dim rsmd As JavaObject =    JO.RunMethod("getMeta", Array ( rs ) ) '
#if java
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.ResultSetMetaData;
 
 public ResultSetMetaData  getMeta(ResultSet rs) throws SQLException {
    ResultSetMetaData rsmd = rs.getMetaData();
    return rsmd;
  }
#End If
From there i can do
B4X:
rsmd.RunMethod("getColumnType", Array(index))
and it works. :eek:

Worth try to access this method with jReflector.
:rolleyes: could be easier with jReflector but me and java not so well...

For the standard prepareCall, the resultSetType is ResultSet.TYPE_FORWARD_ONLY and resultSetConcurrency is ResultSet.CONCUR_READ_ONLY.
Possibly not related to the resulset type itself but the metadata type ( oracle ).


thanks @OliverA , @Erel
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
and it works. :eek:
public ResultSetMetaData getMeta(ResultSet rs) throws SQLException {
Looks like it was just a casting issue. By calling your inline java method, you're recasting rs as a ResultSet object, which allowed you to call the getMetaData method. Good catch!
 
Upvote 0
Top