@@ -150,6 +150,98 @@ public void customRead(String name, String query) throws SQLException {
150150 readSet (leaf , name , query );
151151 }
152152 }
153+ else if ( type == Type .INTEGER || type == Type .FLOAT || type == Type .STRING ) {
154+ readValue (name , query );
155+ }
156+ else
157+ throw new IllegalArgumentException ("Cannot read element " + name + " of type " + type );
158+ }
159+
160+ /** Helper class to execute queries in an exception safe way.
161+ * Use the class via the following template:
162+ * <pre>
163+ final RunQuery q = new RunQuery("SELECT * FROM table;");
164+ try {
165+ ResultSet rs = q.getResult();
166+ ...
167+ }
168+ finally {
169+ q.close();
170+ }
171+ </pre>
172+ * This will correctly clean up and release all resources no matter whether
173+ * an exception is throw or not.
174+ */
175+ private final class RunQuery {
176+ private Connection conn = null ;
177+ private Statement stmt = null ;
178+ private ResultSet rs = null ;
179+ public RunQuery (String query ) throws SQLException {
180+ Connection conn = DriverManager .getConnection (_configuration .getUrl (),
181+ _configuration .getUser (),
182+ _configuration .getPassword ());
183+ Statement stmt = null ;
184+ ResultSet rs = null ;
185+ try {
186+ stmt = conn .createStatement ();
187+ rs = stmt .executeQuery (query );
188+ // Everything worked without problem. Transfer ownership of
189+ // the objects to the newly constructed instance.
190+ this .conn = conn ; conn = null ;
191+ this .stmt = stmt ; stmt = null ;
192+ this .rs = rs ; rs = null ;
193+ }
194+ finally {
195+ if ( rs != null ) rs .close ();
196+ if ( stmt != null ) stmt .close ();
197+ if ( conn != null ) conn .close ();
198+ }
199+ }
200+ public void close () throws SQLException {
201+ rs .close ();
202+ stmt .close ();
203+ conn .close ();
204+ }
205+ ResultSet getResult () { return rs ; }
206+ }
207+
208+ /** Read the scalar value for <code>name</code> from <code>query</code>.
209+ * <b>Note:</b> the function will just use the first value produced by
210+ * <code>query</code> and assign that to the element identified
211+ * by <code>name</code>. If the query produces more than one
212+ * value the surplus values are ignored.
213+ * @param name The name of the element to fill.
214+ * @param query The SQL query that produces the data for <code>name</code>.
215+ * @throws SQLException if querying the database fails or the query does
216+ * not produce at least one value.
217+ */
218+ public void readValue (String name , String query ) throws SQLException {
219+ IloOplElementDefinition def = _def .getElementDefinition (name );
220+ IloOplDataHandler handler = getDataHandler ();
221+ final RunQuery q = new RunQuery (query );
222+ try {
223+ ResultSet rs = q .getResult ();
224+ rs .next ();
225+ handler .startElement (name );
226+ Type type = def .getElementDefinitionType ();
227+ if (type == Type .INTEGER ) {
228+ handler .addIntItem (rs .getInt (1 ));
229+ }
230+ else if (type == Type .FLOAT ) {
231+ handler .addNumItem (rs .getDouble (1 ));
232+ }
233+ else if (type == Type .STRING ) {
234+ handler .addStringItem (rs .getString (1 ));
235+ }
236+ else
237+ throw new IllegalArgumentException ("Cannot load element " + name + " of type " + type );
238+ handler .endElement ();
239+ }
240+ finally {
241+ // We don't use try-with-resources so that we can compile
242+ // with pre-1.8 compilers as well.
243+ q .close ();
244+ }
153245 }
154246
155247 public void readSet (Type leaf , String name , String query ) {
0 commit comments