PostgreSQLにて「trailing junk after parameter at or near」エラーが発生する原因と対処

# はじめに
初投稿になります。
今年入社した一年目の新人エンジニアですので、誤字脱字や内容の誤りなど、お気づきの点は気軽にご指摘ください。
本稿は私の学習の備忘録的なものではありますが、同じ箇所でつまづいた方の手助けになれば幸いです。

# JavaとPostgreSQL
今回私は、JavaによるJSPとサーブレットの仕組みを使用した簡単なWebアプリ開発を行っておりました。データベースシステムはPostgreSQLを使用しています。

# 発生したエラー
サーブレットでデータベースにアクセスする際には、おそらくDAOパターンが用いられることが多いと思います。以下は今回使用したDAOパターンによるメソッドです。
初心者なのでコードの書き方などについて、厳しい指摘はご遠慮ください。。（もちろん、改善案などは歓迎いたします）

```Java:UserLoginDAO.java
public class LoginDAO {
  protected static Connection conn;
  // データベースとの接続情報
  public LoginDAO (Connection conn) {
    LoginDAO.conn = conn;
  }
  
  //　テーブル名
  private static final String TABLE_NAME = " user_table ";
  
  // ログイン認証に使用するためにユーザー固有のIDとパスワードを取得するメソッド
　// 一致しない場合は空のデータが返る
  public UserDTO findUsers(String user_id, String password) throws IllegalArgumentException, InvocationTargetException,
      NoSuchMethodException, SecurityException, SQLException, NamingException {
    UserDTO userRs = new UserDTO();
    String sql = "SELECT" + " user_id," + "user_name FROM" + TABLE_NAME + 
                 "WHERE user_id = ?" + "AND password = ?";
    ResultSet rs = null;
    try (PreparedStatement statement = conn.prepareStatement(sql.toString())) {
      statement.setString(1, user_id);
      statement.setString(2, password);
      rs = statement.executeQuery();
      while(rs.next()) {
        userRs.setUserId(rs.getString("user_id"));
        userRs.setUserName(rs.getString("user_name"));
      }
      return userRs;
    } catch (SQLException e) {
      throw sqlErr(e, sql);
    }
  }
}
```

これを次のように実行したとします。（処理を伝えやすくするために以下のように掲載していますが、実際はもう少し処理が挟まります）
```Java:LoginController.java
String user_id = (String) request.getParameter("loginId");
String password = (String) request.getParameter("loginPassword");
// user_idには"test1"という値を入れました
// passwordには"pass"という値を入れました
findUsers(user_id,password);
```
そこで次のようなエラーメッセージが表示されました。

:::note alert
エラーメッセージ
Caused by: org.postgresql.util.PSQLException: ERROR: trailing junk after parameter at or near "$1A"
:::

おそらく、PostgreSQLのバージョン"15以降"をお使いの方はお気づきかと思います。

ひとまず、検索結果の上から読んでいくことに
[PostgreSQL 15 Press Kit](https://www.postgresql.org/about/press/presskit15/ja/)
を読みましたが、まったくの素人には専門的過ぎてわかりません。

次にこちらを読みました。
[PostgreSQL 15 に関する技術情報](https://www.sraoss.co.jp/tech-blog/pgsql/15-0/)
ここでなにやら気になる文言がいくつかありました。
>数値リテラルの後に続く非数値文字が禁止されました。 (Peter Eisentraut) (15)
これまでは「123abc」のような文字列は「123」とそれに続く「abc」という2つのトークンとして解釈されていました。

ふむふむ
次のようにも書かれていました。

>JSON の数値リテラルの処理が SQL/JSON標準に適合するように変更されました。 (Peter Eisentraut) (15)
「.1」や「1.」 のような数値書式を受け付けるようになります。また、「1.type()」のような数値リテラルにメソッドが続く書き方は禁止されます。

関係あるのかなあ、と悩みました。

# 解決法
以下のページを参考にし、次の箇所を変更しました。
[Postgresql 15 - syntax sensitivity](https://stackoverflow.com/questions/75282073/postgresql-15-syntax-sensitivity)

```diff_Java:LoginDAO.java
-String sql = "SELECT" + " user_id," + "user_name FROM" + TABLE_NAME + 
-              "WHERE user_id = ?" + "AND password = ?";
+String sql = "SELECT" + " user_id," + "user_name FROM" + TABLE_NAME + 
+              "WHERE user_id = ? " + "AND password = ?";
```

user_id = ?"
の?の後ろにスペースを入れただけです。

今回、テストデータとしてuser_idに"test1"という値を入れていたことが原因のようでした。
数値のあとに文字が続いてしまうと、不具合の原因になってしまうようです。
詳しい理由はわかりませんが、今回の不具合に関してはひとまず上記のような対応で大丈夫でした。

PostgreSQLのバージョンが"14"の場合はスペースを入れなくても動くようでしたが、バージョン15以降はこのあたりに気を付けたほうがよさそうです。

# おわりに
私と同じようなエラーにぶつかった方の参考になれば幸いです。
あと、エラーが出た時は根気よく調べると、意外なところで発見があるかもしれません。

初めての記事投稿で疲れてしまいました。

今回はこのあたりで。次こそは有益な記事が書けるように頑張ります。