class Database implements IVariables, ILoggingObject {

  public IRowMeta getQueryFieldsFallback( String sql, boolean param, IRowMeta inform,
                                          Object[] data ) throws HopDatabaseException {
    IRowMeta fields;

    try {
      if ( ( inform == null
        // Hack for MSSQL jtds 1.2 when using xxx NOT IN yyy we have to use a
        // prepared statement (see BugID 3214)
        && databaseMeta.getIDatabase().isMsSqlServerVariant() )
        || databaseMeta.getIDatabase().supportsResultSetMetadataRetrievalOnly() ) {
        sel_stmt = connection.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY );
        try {
          if ( databaseMeta.isFetchSizeSupported() && sel_stmt.getMaxRows() >= 1 ) {
            if ( databaseMeta.getIDatabase().isMySqlVariant() ) {
              sel_stmt.setFetchSize( Integer.MIN_VALUE );
            } else {
              sel_stmt.setFetchSize( 1 );
            }
          }
          if ( databaseMeta.supportsSetMaxRows() ) {
            sel_stmt.setMaxRows( 1 );
          }

          ResultSet r = sel_stmt.executeQuery( databaseMeta.stripCR( sql ) );
          try {
            fields = getRowInfo( r.getMetaData(), false, false );
          } finally { // avoid leaking resources
            r.close();
          }
        } finally { // avoid leaking resources
          sel_stmt.close();
          sel_stmt = null;
        }
      } else {
        PreparedStatement ps = connection.prepareStatement( databaseMeta.stripCR( sql ) );
        try {
          if ( param ) {
            IRowMeta par = inform;

            if ( par == null || par.isEmpty() ) {
              par = getParameterMetaData( ps );
            }

            if ( par == null || par.isEmpty() ) {
              par = getParameterMetaData( sql, inform, data );
            }

            setValues( par, data, ps );
          }
          ResultSet r = ps.executeQuery();
          try {
            //
            // See PDI-14893
            // If we're in this private fallback method, it's because the databasemeta returns false for
            // supportsPreparedStatementMetadataRetrieval() or because we got an exception trying to do
            // it the other way. In either case, there is no reason for us to ever try getting the prepared
            // statement's metadata. The right answer is to directly get the resultset metadata.
            //
            // ResultSetMetaData metadata = ps.getMetaData();
            // If the PreparedStatement can't get us the metadata, try using the ResultSet's metadata
            // if ( metadata == null ) {
            //  metadata = r.getMetaData();
            // }
            ResultSetMetaData metadata = r.getMetaData();
            fields = getRowInfo( metadata, false, false );
          } finally { // should always use a try/finally to avoid leaks
            r.close();
          }
        } finally { // should always use a try/finally to avoid leaks
          ps.close();
        }
      }
    } catch ( Exception ex ) {
      throw new HopDatabaseException( "Couldn't get field info from [" + sql + "]" + Const.CR, ex );
    }

    return fields;
  }

  @Deprecated public  Database( DatabaseMeta databaseMeta );
  public  Database( ILoggingObject parentObject, DatabaseMeta databaseMeta );

}