@@ -279,28 +279,99 @@ public void deleteTable(String tableName) {
279279 }
280280 }
281281
282- public void executeQuery (String sql ) {
283- logger .warn ("Executing raw command: " + sql );
284- try (Statement statement = getConnection ().createStatement ()) {
285- statement .execute (sql );
282+ public List <Map <String , Object >> executeQuery (String sql ) {
283+ logger .warn ("Executing raw query: " + sql );
284+ List <Map <String , Object >> results = new ArrayList <>();
285+
286+ try (Statement stmt = getConnection ().createStatement ();
287+ ResultSet rs = stmt .executeQuery (sql )) {
288+
289+ ResultSetMetaData metaData = rs .getMetaData ();
290+ int columnCount = metaData .getColumnCount ();
291+
292+ while (rs .next ()) {
293+ Map <String , Object > row = new LinkedHashMap <>();
294+ for (int i = 1 ; i <= columnCount ; i ++) {
295+ String colName = metaData .getColumnLabel (i );
296+ if (colName == null || colName .isEmpty ()) {
297+ colName = metaData .getColumnName (i );
298+ }
299+ row .put (colName , rs .getObject (i ));
300+ }
301+ results .add (row );
302+ }
303+
304+ logger .debug ("Query returned " + results .size () + " rows" );
305+ return results ;
286306 } catch (SQLException e ) {
307+ logger .error ("Query failed: " + e .getMessage () + " [SQL: " + sql + "]" );
287308 throw new RuntimeException (e );
288309 }
289310 }
290311
291- public void executeQuery (String sql , List <?> params ) {
312+ public List < Map < String , Object >> executeQuery (String sql , List <?> params ) {
292313 logger .warn ("Executing parameterized query: " + sql );
314+ List <Map <String , Object >> results = new ArrayList <>();
315+
293316 try (PreparedStatement pstmt = getConnection ().prepareStatement (sql )) {
294317 bindParameters (pstmt , params );
295- pstmt .execute ();
318+
319+ try (ResultSet rs = pstmt .executeQuery ()) {
320+ ResultSetMetaData metaData = rs .getMetaData ();
321+ int columnCount = metaData .getColumnCount ();
322+
323+ while (rs .next ()) {
324+ Map <String , Object > row = new LinkedHashMap <>();
325+ for (int i = 1 ; i <= columnCount ; i ++) {
326+ String colName = metaData .getColumnLabel (i );
327+ if (colName == null || colName .isEmpty ()) {
328+ colName = metaData .getColumnName (i );
329+ }
330+ row .put (colName , rs .getObject (i ));
331+ }
332+ results .add (row );
333+ }
334+ }
335+
336+ logger .debug ("Query returned " + results .size () + " rows" );
337+ return results ;
296338 } catch (SQLException e ) {
297339 logger .error ("Query failed: " + e .getMessage () + " [SQL: " + sql + "]" );
298340 throw new RuntimeException (e );
299341 }
300342 }
301343
302- public void executeQuery (String sql , Object ... params ) {
303- executeQuery (sql , Arrays .asList (params ));
344+ public List <Map <String , Object >> executeQuery (String sql , Object ... params ) {
345+ return executeQuery (sql , Arrays .asList (params ));
346+ }
347+
348+ public int executeUpdate (String sql ) {
349+ logger .warn ("Executing update: " + sql );
350+ try (Statement stmt = getConnection ().createStatement ()) {
351+ int affected = stmt .executeUpdate (sql );
352+ logger .debug ("Update affected " + affected + " rows" );
353+ return affected ;
354+ } catch (SQLException e ) {
355+ logger .error ("Update failed: " + e .getMessage () + " [SQL: " + sql + "]" );
356+ throw new RuntimeException (e );
357+ }
358+ }
359+
360+ public int executeUpdate (String sql , List <?> params ) {
361+ logger .warn ("Executing parameterized update: " + sql );
362+ try (PreparedStatement pstmt = getConnection ().prepareStatement (sql )) {
363+ bindParameters (pstmt , params );
364+ int affected = pstmt .executeUpdate ();
365+ logger .debug ("Update affected " + affected + " rows" );
366+ return affected ;
367+ } catch (SQLException e ) {
368+ logger .error ("Update failed: " + e .getMessage () + " [SQL: " + sql + "]" );
369+ throw new RuntimeException (e );
370+ }
371+ }
372+
373+ public int executeUpdate (String sql , Object ... params ) {
374+ return executeUpdate (sql , Arrays .asList (params ));
304375 }
305376
306377 public int upsertData (String tableName , List <String > conflictColumns , Map <String , Object > insertData ) {
@@ -347,22 +418,22 @@ public int upsertData(String tableName, List<String> conflictColumns, Map<String
347418
348419 sql = String .format (
349420 "INSERT INTO %s (%s) VALUES (%s) ON CONFLICT (%s) DO UPDATE SET %s" ,
350- quoteIdentifier (tableName ), // table
351- String .join (", " , insertColumns ), // (col1, col2)
352- String .join (", " , Collections .nCopies (insertColumns .size (), "?" )), // (?, ?)
353- String .join (", " , conflictColumns .stream ().map (this ::quoteIdentifier ).toArray (String []::new )), // conflict cols (quoted)
354- String .join (", " , updateAssignments ) // col = excluded.col, ...
421+ quoteIdentifier (tableName ),
422+ String .join (", " , insertColumns ),
423+ String .join (", " , Collections .nCopies (insertColumns .size (), "?" )),
424+ String .join (", " , conflictColumns .stream ().map (this ::quoteIdentifier ).toArray (String []::new )),
425+ String .join (", " , updateAssignments )
355426 );
356427 break ;
357428
358429 case MYSQL :
359430 for (String col : insertColumns ) {
360431 String unquotedCol = col ;
361- if (col .startsWith ("`" ) && col .endsWith ("`" )) { // Basic unquoting if needed
432+ if (col .startsWith ("`" ) && col .endsWith ("`" )) {
362433 unquotedCol = col .substring (1 , col .length () - 1 );
363434 }
364435 if (!conflictColumns .contains (unquotedCol )) {
365- updateAssignments .add (col + " = VALUES(" + col + ")" ); // Use quoted identifier
436+ updateAssignments .add (col + " = VALUES(" + col + ")" );
366437 }
367438 }
368439 if (updateAssignments .isEmpty ()) {
@@ -449,7 +520,6 @@ public int insertData(String tableName, Object... columnsAndValues) {
449520 return insertData (tableName , insertData );
450521 }
451522
452- // Helper method using MapUtils
453523 public int insertData (String tableName , LinkedHashMap <String , Object > insertData ) {
454524 return insertData (tableName , (Map <String , Object >) insertData );
455525 }
@@ -944,4 +1014,49 @@ public boolean tableExists(String tableName) {
9441014 throw new RuntimeException (e );
9451015 }
9461016 }
1017+
1018+ public long count (String tableName ) {
1019+ return count (tableName , null );
1020+ }
1021+
1022+ public long count (String tableName , Map <String , Object > whereClause ) {
1023+ validateIdentifier (tableName );
1024+
1025+ StringBuilder sql = new StringBuilder ("SELECT COUNT(*) FROM " )
1026+ .append (quoteIdentifier (tableName ));
1027+
1028+ List <Object > whereValues = new ArrayList <>();
1029+ if (whereClause != null && !whereClause .isEmpty ()) {
1030+ List <String > whereConditions = new ArrayList <>();
1031+ for (Map .Entry <String , Object > entry : whereClause .entrySet ()) {
1032+ validateIdentifier (entry .getKey ());
1033+ whereConditions .add (quoteIdentifier (entry .getKey ()) +
1034+ (entry .getValue () == null ? " IS ?" : " = ?" ));
1035+ whereValues .add (entry .getValue ());
1036+ }
1037+ sql .append (" WHERE " ).append (String .join (" AND " , whereConditions ));
1038+ }
1039+
1040+ String sqlString = sql .toString ();
1041+ logger .debug ("Executing count: " + sqlString );
1042+
1043+ try (PreparedStatement pstmt = getConnection ().prepareStatement (sqlString )) {
1044+ if (!whereValues .isEmpty ()) {
1045+ bindParameters (pstmt , whereValues );
1046+ }
1047+
1048+ try (ResultSet rs = pstmt .executeQuery ()) {
1049+ if (rs .next ()) {
1050+ long count = rs .getLong (1 );
1051+ logger .debug ("Count returned: " + count );
1052+ return count ;
1053+ }
1054+ return 0 ;
1055+ }
1056+ } catch (SQLException e ) {
1057+ logger .error ("Count failed for table '" + tableName + "': " +
1058+ e .getMessage () + " [SQL: " + sqlString + "]" );
1059+ throw new RuntimeException (e );
1060+ }
1061+ }
9471062}
0 commit comments