Home > Software engineering >  ERROR: column is of type bit but expression is of type boolean
ERROR: column is of type bit but expression is of type boolean

Time:01-30

The database have an attribute with type BIT(1) where the value can be '0'/'1', I have an hibernate entity that have an attribute:

  private Boolean attribute;

What i tried:

But I only receive errors like

ERROR: column  is of type bit but expression is of type boolean
ERROR: column  is of type bit but expression is of type bytea
ERROR: column is of type bit but expression is of type various
ERROR: column is of type bit but expression is of type string

CodePudding user response:

At first glance, I would try using the following @Column definition for your field:

@Column(columnDefinition="bit")
private Boolean attribute;

If it doesn't work, although I am aware that you mentioned you tested it in your question, try defining a custom @Type. The idea is based on this other SO question, the following test case, and this article from Vlad Mihalcea.

Your custom type definition could be as follows:

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

public class PostgresBit1Type
    extends ImmutableType<Boolean> {

  public PostgresBit1Type() {
    super(Boolean.class);
  }

  @Override
  public int[] sqlTypes() {
    return new int[]{Types.BIT};
  }

  @Override
  public Boolean get(
      ResultSet rs,
      String[] names,
      SharedSessionContractImplementor session,
      Object owner)
      throws SQLException {
    // The paradox is that the driver itself treats BIT(1) as boolean
    Boolean result = rs.getBoolean(names[0]);
    return result;
  }

  @Override
  public void set(
      PreparedStatement st,
      Point value,
      int index,
      SharedSessionContractImplementor session)
      throws SQLException {
    if (value == null) {
      st.setNull(index, Types.BIT);
    } else {
      Object holder = ReflectionUtils.newInstance(
        "org.postgresql.util.PGobject"
      );
      ReflectionUtils.invokeSetter(
        holder,
        "type",
        "bit"
      );
      ReflectionUtils.invokeSetter(
        holder,
        "value",
        value ? "1" : "0"
      );
      st.setObject(index, holder);
    }
  }
}

As mentioned in the companion SO answer, the Inmutable class is taken from this excellent article from Vlad Mihalcea:

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;

import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;

public abstract class ImmutableType<T> implements UserType {

  private final Class<T> clazz;

  protected ImmutableType(Class<T> clazz) {
    this.clazz = clazz;
  }

  @Override
  public Object nullSafeGet(
      ResultSet rs,
      String[] names,
      SharedSessionContractImplementor session,
      Object owner)
      throws SQLException {
    return get(rs, names, session, owner);
  }

  @Override
  public void nullSafeSet(
      PreparedStatement st,
      Object value,
      int index,
      SharedSessionContractImplementor session)
      throws SQLException {
    set(st, clazz.cast(value), index, session);
  }

  protected abstract T get(
      ResultSet rs,
      String[] names,
      SharedSessionContractImplementor session,
      Object owner) throws SQLException;

  protected abstract void set(
      PreparedStatement st,
      T value,
      int index,
      SharedSessionContractImplementor session)
      throws SQLException;


  @Override
  public Class<T> returnedClass() {
    return clazz;
  }

  @Override
  public boolean equals(Object x, Object y) {
    return Objects.equals(x, y);
  }

  @Override
  public int hashCode(Object x) {
    return x.hashCode();
  }

  @Override
  public Object deepCopy(Object value) {
    return value;
  }

  @Override
  public boolean isMutable() {
    return false;
  }

  @Override
  public Serializable disassemble(Object o) {
    return (Serializable) o;
  }

  @Override
  public Object assemble(
      Serializable cached,
      Object owner) {
    return cached;
  }

  @Override
  public Object replace(
      Object o,
      Object target,
      Object owner) {
    return o;
  }
}

Finally, define your Boolean field similar to:

@Type(type = "your.packg.PostgresBit1Type")
@Column(columnDefinition = "bit")
public Boolean attribute;

I recommend to use Boolean and not boolean to appropriately handle null. values.

Although I think it should work I haven't tested the solution myself. I hope at least it gives you some clues to advance in the problem resolution.

CodePudding user response:

**

First to clarify things:

**

The Java Boolean represents a single bit value that can be 0 or 1 (False or True).

Whereas SQL defines an SQL BIT type. However, unlike what you expect, BIT in SQL can be used as a parameterized type to define a fixed-length binary string (not just 0 or 1 it can be 00000, 00001, 01010... etc.).

so that's why it might bring you problems while you map them.


However, try this:

@Column(name = "columnName", columnDefinition="BIT")
private Boolean columnVariable;

or this:

@Type(type = "numeric_boolean")
private Boolean columnVariable; 
  •  Tags:  
  • Related