@@ -158,13 +158,17 @@ public ConvexSchema getSchema() {
158158 * Execute INSERT - called from ConvexTableModify generated code.
159159 */
160160 public long executeInsert (Enumerable <Object []> input ) {
161- long count = 0 ;
162- for (Object [] row : input ) {
163- if (row != null && insertRow (row )) {
164- count ++;
161+ try {
162+ long count = 0 ;
163+ for (Object [] row : input ) {
164+ if (row != null && insertRow (row )) {
165+ count ++;
166+ }
165167 }
168+ return count ;
169+ } catch (ExceptionInInitializerError e ) {
170+ throw wrapTypeError (e , "INSERT" );
166171 }
167- return count ;
168172 }
169173
170174 /**
@@ -177,73 +181,96 @@ public long executeInsert(Enumerable<Object[]> input) {
177181 * <p>Type validation is performed on updated columns.
178182 */
179183 public long executeUpdate (Enumerable <Object []> input , int columnCount , int [] updateIndices ) {
180- // Check if PK column (index 0) is being updated
181- boolean pkBeingUpdated = false ;
182- for (int idx : updateIndices ) {
183- if (idx == 0 ) {
184- pkBeingUpdated = true ;
185- break ;
184+ try {
185+ // Check if PK column (index 0) is being updated
186+ boolean pkBeingUpdated = false ;
187+ for (int idx : updateIndices ) {
188+ if (idx == 0 ) {
189+ pkBeingUpdated = true ;
190+ break ;
191+ }
186192 }
187- }
188193
189- ConvexColumnType [] types = getColumnTypes ();
194+ ConvexColumnType [] types = getColumnTypes ();
190195
191- long count = 0 ;
192- for (Object [] row : input ) {
193- if (row == null ) continue ;
196+ long count = 0 ;
197+ for (Object [] row : input ) {
198+ if (row == null ) continue ;
194199
195- // Reconstruct updated row from Calcite's format:
196- // [original columns..., new values for updated columns...]
197- Object [] updatedRow = new Object [columnCount ];
198- for (int i = 0 ; i < columnCount ; i ++) {
199- updatedRow [i ] = row [i ];
200- }
201- for (int i = 0 ; i < updateIndices .length ; i ++) {
202- int targetIdx = updateIndices [i ];
203- if (targetIdx >= 0 && targetIdx < columnCount ) {
204- // Validate type before assignment
205- Object newValue = row [columnCount + i ];
206- ConvexColumnType type = (types != null && targetIdx < types .length ) ? types [targetIdx ] : ConvexColumnType .of (ConvexType .ANY );
207- type .toCell (newValue ); // Validates type, throws if invalid
208- updatedRow [targetIdx ] = newValue ;
200+ // Reconstruct updated row from Calcite's format:
201+ // [original columns..., new values for updated columns...]
202+ Object [] updatedRow = new Object [columnCount ];
203+ for (int i = 0 ; i < columnCount ; i ++) {
204+ updatedRow [i ] = row [i ];
205+ }
206+ for (int i = 0 ; i < updateIndices .length ; i ++) {
207+ int targetIdx = updateIndices [i ];
208+ if (targetIdx >= 0 && targetIdx < columnCount ) {
209+ // Validate type before assignment
210+ Object newValue = row [columnCount + i ];
211+ ConvexColumnType type = (types != null && targetIdx < types .length ) ? types [targetIdx ] : ConvexColumnType .of (ConvexType .ANY );
212+ type .toCell (newValue ); // Validates type, throws if invalid
213+ updatedRow [targetIdx ] = newValue ;
214+ }
209215 }
210- }
211216
212- ACell oldPk = toCell (row [0 ], 0 );
213- ACell newPk = toCell (updatedRow [0 ], 0 );
217+ ACell oldPk = toCell (row [0 ], 0 );
218+ ACell newPk = toCell (updatedRow [0 ], 0 );
214219
215- // If PK is being changed, check for uniqueness violation
216- if (pkBeingUpdated && !oldPk .equals (newPk )) {
217- // Check if new PK already exists
218- if (schema .getTables ().selectByKey (tableName , newPk ) != null ) {
219- throw new RuntimeException ("Unique constraint violation: primary key '" +
220- newPk + "' already exists in table '" + tableName + "'" );
220+ // If PK is being changed, check for uniqueness violation
221+ if (pkBeingUpdated && !oldPk .equals (newPk )) {
222+ // Check if new PK already exists
223+ if (schema .getTables ().selectByKey (tableName , newPk ) != null ) {
224+ throw new RuntimeException ("Unique constraint violation: primary key '" +
225+ newPk + "' already exists in table '" + tableName + "'" );
226+ }
221227 }
222- }
223228
224- // Delete old row by ORIGINAL PK, then insert with new values
225- schema .getTables ().deleteByKey (tableName , oldPk );
226- if (insertRow (updatedRow )) {
227- count ++;
229+ // Delete old row by ORIGINAL PK, then insert with new values
230+ schema .getTables ().deleteByKey (tableName , oldPk );
231+ if (insertRow (updatedRow )) {
232+ count ++;
233+ }
228234 }
235+ return count ;
236+ } catch (ExceptionInInitializerError e ) {
237+ throw wrapTypeError (e , "UPDATE" );
229238 }
230- return count ;
231239 }
232240
233241 /**
234242 * Execute DELETE - called from ConvexTableModify generated code.
235243 */
236244 public long executeDelete (Enumerable <Object []> input ) {
237- long count = 0 ;
238- for (Object [] row : input ) {
239- if (row != null && row .length > 0 ) {
240- ACell pk = toCell (row [0 ], 0 );
241- if (schema .getTables ().deleteByKey (tableName , pk )) {
242- count ++;
245+ try {
246+ long count = 0 ;
247+ for (Object [] row : input ) {
248+ if (row != null && row .length > 0 ) {
249+ ACell pk = toCell (row [0 ], 0 );
250+ if (schema .getTables ().deleteByKey (tableName , pk )) {
251+ count ++;
252+ }
243253 }
244254 }
255+ return count ;
256+ } catch (ExceptionInInitializerError e ) {
257+ throw wrapTypeError (e , "DELETE" );
258+ }
259+ }
260+
261+ /**
262+ * Wraps type conversion errors from Calcite's generated code into a RuntimeException
263+ * with a clear SQL error message. Avatica will convert this to SQLException.
264+ */
265+ private RuntimeException wrapTypeError (ExceptionInInitializerError e , String operation ) {
266+ Throwable cause = e .getCause ();
267+ String message = "Type conversion error in " + operation + " on table '" + tableName + "'" ;
268+ if (cause instanceof NumberFormatException nfe ) {
269+ message += ": invalid number format - " + nfe .getMessage ();
270+ } else if (cause != null ) {
271+ message += ": " + cause .getMessage ();
245272 }
246- return count ;
273+ return new RuntimeException ( message , e ) ;
247274 }
248275
249276 private boolean insertRow (Object [] row ) {
0 commit comments