Troubleshooting checklist :
#1 : Depending on the database type you are using you would want to find the the column
names and their respective data types using this SQL command :
SELECT
table_name,
column_name,
data_type
FROM
information_schema.columns
WHERE
table_name = 'the-name-of-the-table-in-the-database';
Expected results would give you three columns; and more especially the ‘data_type’ column.
Make sure your Pojo class and the respective data types match appropriately.
Take note : bigint (data type) in the table inside the database can match with a Long seamlessly.
integer with int. character varying with String or a major java class, eg. a class storing Enums, and so on.
After confirming the above, do the next check -> troubleshooting :
#2 : The Main checks on this troubleshooting is to check that all the data types match
perfectly. And do pay attention to the parameters passed to the query.
Passing an enum
or or any other data type or an enum type that is not conforming to the SQL data types
could trigger the ‘is not mapped’ error(s) even if the pojo class matches perfectly with
the table structure in the database.
pojo example : UserAccountBalance.class
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
@Builder//Lombok
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@Data//Lombok
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Schema
@Entity(name = "user_account_balance")
@Table(name = "user_account_balance")
public class UserAccountBalance {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private long id;
@NotNull
@Column(name = "username", nullable = false)
private String userName;
@NotNull
@Column(name="currency_code", nullable = false)
@Enumerated(EnumType.STRING)
private CurrencyCode currencyCode;
@NotNull
@Column(name = "balance", nullable = false)
private BigDecimal balance;
//Could be placed into and AuditModel class
@Column(name = "datecreated", nullable = false, updatable = false)
@JsonIgnore
@DateCreated
@CreationTimestamp
private LocalDateTime dateCreated;
@Column(name = "date_updated", nullable = false, updatable = false)
@JsonIgnore
@DateUpdated
private LocalDateTime dateUpdated;
@NotNull
@Column(name = "active")
@JsonIgnore
private int active;
@Column(name = "deleted")
@JsonIgnore
private int deleted;
}
Repository class :
//Option 1 : UserAccountBalanceRepository.class
@Repository
public abstract class UserAccountBalanceRepository implements CrudRepository<UserAccountBalance, Long> {
private final EntityManager entityManager;
public UserAccountBalanceRepository(@CurrentSession EntityManager entityManager){
this.entityManager = entityManager;
}
@Transactional(readOnly = true)
@Query(
value="SELECT uab.*" +
" FROM public.user_account_balance uab" +
" WHERE (currency_code =cast(:currencyCode AS text)" +
" AND userName =:userName" +
" AND active =:active)",
countQuery = "SELECT uab.*" +
" FROM public.user_account_balance uab" +
" WHERE (currency_code = cast(:currencyCode AS text)" +
" AND userName =:userName" +
" AND active =:active)",
nativeQuery = true
)
public abstract Optional<UserAccountBalance> findByUserAccountBalance_UserName_And_CurrencyCode(
String userName,
CurrencyCode currencyCode,
int active
);
}
//Option 2 : UserAccountBalanceRepository.class
@Repository
public abstract class UserAccountBalanceRepository implements CrudRepository<UserAccountBalance, Long> {
private final EntityManager entityManager;
public UserAccountBalanceRepository(@CurrentSession EntityManager entityManager){
this.entityManager = entityManager;
}
@Transactional(readOnly = true)
@Query(
value="SELECT uab.*" +
" FROM public.user_account_balance uab" +
" WHERE (currency_code =:currencyCode" +
" AND userName =:userName" +
" AND active =:active)",
countQuery = "SELECT uab.*" +
" FROM public.user_account_balance uab" +
" WHERE (currency_code = :currencyCode" +
" AND userName =:userName" +
" AND active =:active)",
nativeQuery = true
)
public abstract Optional<UserAccountBalance> findByUserAccountBalance_UserName_And_CurrencyCode(
String userName,
String currencyCode,/*this is what truly worked out for me perfectly*/
int active
);
}
#3. Test and test again. If problem still persist please have patience and look through all
your variables and classes again.
#4. If troubleshooting using option #3 still does not help, consider taking a little walk, take
some little rest and have a fresh set of eyes to look at it all over from troubleshooting #1.
I hope this helps. Cheers and peace.
Troubleshooting checklist :
#1 : Depending on the database type you are using you would want to find the the column
names and their respective data types using this SQL command :
SELECT
table_name,
column_name,
data_type
FROM
information_schema.columns
WHERE
table_name = 'the-name-of-the-table-in-the-database';
Expected results would give you three columns; and more especially the ‘data_type’ column.
Make sure your Pojo class and the respective data types match appropriately.
Take note : bigint (data type) in the table inside the database can match with a Long seamlessly.
integer with int. character varying with String or a major java class, eg. a class storing Enums, and so on.
After confirming the above, do the next check -> troubleshooting :
#2 : The Main checks on this troubleshooting is to check that all the data types match
perfectly. And do pay attention to the parameters passed to the query.
Passing an enum
or or any other data type or an enum type that is not conforming to the SQL data types
could trigger the ‘is not mapped’ error(s) even if the pojo class matches perfectly with
the table structure in the database.
pojo example : UserAccountBalance.class
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
@Builder//Lombok
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PUBLIC)
@Data//Lombok
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Schema
@Entity(name = "user_account_balance")
@Table(name = "user_account_balance")
public class UserAccountBalance {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private long id;
@NotNull
@Column(name = "username", nullable = false)
private String userName;
@NotNull
@Column(name="currency_code", nullable = false)
@Enumerated(EnumType.STRING)
private CurrencyCode currencyCode;
@NotNull
@Column(name = "balance", nullable = false)
private BigDecimal balance;
//Could be placed into and AuditModel class
@Column(name = "datecreated", nullable = false, updatable = false)
@JsonIgnore
@DateCreated
@CreationTimestamp
private LocalDateTime dateCreated;
@Column(name = "date_updated", nullable = false, updatable = false)
@JsonIgnore
@DateUpdated
private LocalDateTime dateUpdated;
@NotNull
@Column(name = "active")
@JsonIgnore
private int active;
@Column(name = "deleted")
@JsonIgnore
private int deleted;
}
Repository class :
//Option 1 : UserAccountBalanceRepository.class
@Repository
public abstract class UserAccountBalanceRepository implements CrudRepository<UserAccountBalance, Long> {
private final EntityManager entityManager;
public UserAccountBalanceRepository(@CurrentSession EntityManager entityManager){
this.entityManager = entityManager;
}
@Transactional(readOnly = true)
@Query(
value="SELECT uab.*" +
" FROM public.user_account_balance uab" +
" WHERE (currency_code =cast(:currencyCode AS text)" +
" AND userName =:userName" +
" AND active =:active)",
countQuery = "SELECT uab.*" +
" FROM public.user_account_balance uab" +
" WHERE (currency_code = cast(:currencyCode AS text)" +
" AND userName =:userName" +
" AND active =:active)",
nativeQuery = true
)
public abstract Optional<UserAccountBalance> findByUserAccountBalance_UserName_And_CurrencyCode(
String userName,
CurrencyCode currencyCode,
int active
);
}
//Option 2 : UserAccountBalanceRepository.class
@Repository
public abstract class UserAccountBalanceRepository implements CrudRepository<UserAccountBalance, Long> {
private final EntityManager entityManager;
public UserAccountBalanceRepository(@CurrentSession EntityManager entityManager){
this.entityManager = entityManager;
}
@Transactional(readOnly = true)
@Query(
value="SELECT uab.*" +
" FROM public.user_account_balance uab" +
" WHERE (currency_code =:currencyCode" +
" AND userName =:userName" +
" AND active =:active)",
countQuery = "SELECT uab.*" +
" FROM public.user_account_balance uab" +
" WHERE (currency_code = :currencyCode" +
" AND userName =:userName" +
" AND active =:active)",
nativeQuery = true
)
public abstract Optional<UserAccountBalance> findByUserAccountBalance_UserName_And_CurrencyCode(
String userName,
String currencyCode,/*this is what truly worked out for me perfectly*/
int active
);
}
#3. Test and test again. If problem still persist please have patience and look through all
your variables and classes again.
#4. If troubleshooting using option #3 still does not help, consider taking a little walk, take
some little rest and have a fresh set of eyes to look at it all over from troubleshooting #1.
I hope this helps. Cheers and peace.
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and
privacy statement. We’ll occasionally send you account related emails.
Already on GitHub?
Sign in
to your account
Closed
Unigang opened this issue
Dec 11, 2015
· 4 comments
Comments
I test this query for jsonb data in pgAdmin , it work fine.
var cmd = conn.CreateCommand();
cmd.CommandText = «SELECT (data->>’ProductPrice’) AS price FROM order_data»;
var reader = cmd.ExecuteReader();
42883: operator does not exist: character varying ->> unknown
No operator matches the given name and argument type(s). You might need to add explicit type casts.
Are you sure that your data column is of type jsonb? PostgreSQL seems to be complaining that data is a varchar
Yes , this column is jsonb .
I can’t reproduce this error, I strongly suspect there’s some sort of misunderstanding, i.e. you’re not querying the table or column you think you are. PostgreSQL is telling you that «data» is a «character varying» and not a jsonb, can you please double-check your schema? You can also post a dump of your database schema (with pgdump --schema-only
) if you want.
I’m very sorry for waste your time.
I misunderstanding of table , I check table again this column is varchar.
2 participants
The error org.postgresql.util.PSQLException: ERROR: operator does not exist: my_enum_type = character varying can be fixed by using implicit conversions in PostgreSQL or using explicit conversions by passing the java.sql.Types.OTHER to Spring JDBC.
The exception you will receive
When using Spring JDBC or Spring Data JDBC and custom Java enum types, you might run into the following problem:
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT * FROM your_table where enum_column = :enum_value;] nested exception is org.postgresql.util.PSQLException: ERROR: operator does not exist: my_enum_type = character varying Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
The exception can occur if you are having enums with either
- or you are trying to persist an Spring Data JDBC entity with a repository save method
- executing a query on your own with one of Spring JDBC’s jdbcTemplate methods like query
Making Spring Data JDBC’s save method work with enumerations
With Spring Data JDBC you have probably an SQL definition like
CREATE TYPE my_enum_type AS ENUM('VALUE_1','VALUE_2') CREATE TABLE my_table (enum_column my_enum_type);
The belonging Java source code will look like
public enum MyEnumType { VALUE_1, VALUE_2 } @Table("my_table") public class MyEntity { private MyEnumType type; // getter & setter ... } @Repository public class MyTableRepository extends CrudRepository</* ... */> { } @Controller public class MyTableController { @Autowired MyTableRepository @GetMapping("/") public void save() { MyEntity entity = new MyEntity(); entity.setType(MyEnumType.VALUE_1); repository.save(entity); } }
As soon as you try to call repository.save you will receive an exception. The problem is, that Spring Data JDBC does not support enumerations at the moment. See Jens Schauder’s answer at stackoverflow.
Jens does also link to another SO answer which describes how to solve the problem. To make the code sample above working, we can use PostgreSQL’s implicit conversion feature as described in the linked answer. The following SQL definition would reside somewhere in your Liquibase or Flyway migration definition:
<!-- Liquibase migration definition --> <!-- as described above --> <sql>CREATE TYPE my_enum_type AS ENUM('VALUE_1','VALUE_2')</sql> <!-- add an additional type --> <sql>CREATE CAST (varchar AS my_enum_type) WITH INOUT AS IMPLICIT</sql>
With help of the described CREATE CAST PostgreSQL will automatically try convert each String/varchar into the specified enum. You can now do something like
SELECT * FROM my_table WHERE enum_column = 'VALUE_1'; -- OR INSERT INTO my_table(enum_column) VALUES('VALUE_1')
After that, repository.save() will work.
Using JdbcTemplate and enumerations
You might think that the specified CREATE CAST definition would also work for something like that:
public class MyRepository { @Autowired NamedParameterJdbcTemplate jdbcTemplate; public List<String> findAll() { MapSqlParameterSource parameters = new MapSqlParameterSource("type", MyEnumType.VALUE_1); return jdbcTemplate .queryForList("SELECT enum_column FROM my_table WHERE enum_column = :type", parameters); } }
But this will drive you right into the exception you find at the beginning:
org.postgresql.util.PSQLException: ERROR: operator does not exist: my_enum_type = character varying
The reason for this behavior is how PostgreSQL handles the type casts. This Stackoverflow answer describes the reasons in detail. Spring JDBC does automatically convert the enum value into a Java String type and assigns it to the prepared statement. The underlying PgJDBC drivers then assigns the java.sql.Type.VARCHAR as type for this prepared statement parameter. Due to the assignment of the java.sql.Type, PostgreSQL will no longer try to apply our CREATE CAST conversion.
Solving it by configuration
You can configure your JDBC URL to use the parameter stringtype with value undefined. Each String parameter previously set with setString() will then not have the type definition java.sql.Type.VARCHAR. PostgreSQL applies will then apply our CREATE CAST definition.
Solving it programatically
If you don’t globally want to set stringtype to undefined, you have to use the java.sql.Types.OTHER when adding a value to the MapSqlParameterSource:
// does NOT WORK: // .addValue("type", MyEnumType.VALUE_1)) // one of the following does work: .addValue("type", "VALUE_1", java.sql.Types.OTHER) // or .addValue("type", MyEnumType.VALUE_1.getName(), java.sql.Types.OTHER) // or .addValue("type", MyEnumType.VALUE_1, java.sql.Types.OTHER)
To make it more convenient, you can extend from MapSqlParameterSource to get something like this:
public static class CustomMapSqlParameterSource extends MapSqlParameterSource { public CustomMapSqlParameterSource addEnum(String paramName, Object value) { if (!value.getClass().isEnum()) { throw new IllegalArgumentException("Given parameter is not of Java type enum"); } addValue(paramName, value, java.sql.Types.OTHER); return this; } }
Wrapping it up
This blog post showed you, how you can use native PostgreSQL enumerations with native Java and make them both work with Spring Data JDBC and Spring JDBC.
У меня есть вот такая таблица в базе данных
CREATE TABLE public."Releases" (
id uuid NOT NULL,
name character varying(150) COLLATE pg_catalog."default" NOT NULL,
english character varying(150) COLLATE pg_catalog."default",
synonyms character varying(150)[] COLLATE pg_catalog."default" NOT NULL DEFAULT (ARRAY[]::character varying[])::character varying(150)[]
) WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public."Releases"
OWNER to postgres;
Реализовать поиск с использованием ILIKE для полей name, english очень просто. Только вот теперь понадобился поиск по массиву synonyms, и вот тут соответственно возникла ситуация при таком запросе:
SELECT * FROM "public"."Releases" WHERE synonyms ILIKE '%test%'
Возникает ошибка:
ОШИБКА: оператор не существует: character varying[] ~~* unknown
СТРОКА 1: SELECT * FROM "public"."Releases" WHERE synonyms ILIKE '%tes...
^
ПОДСКАЗКА: Оператор с данными именем и типами аргументов не найден. Возможно, вам следует добавить явные приведения типов.
Так вот как именно отредактировать запрос, чтобы добавить это поведение?