Db2 luwでEBCDIC並び順のサポート

## Db2 luwでのEBCDIC照合順序のサポート
アプリケーションの都合によってEBCDIC並びをluwプラットフォームで実現したい場合があります。Db2luwでは、CREATE DATABASEを行うときにCODESE、TERRITORYとCOLLATEを指定することで決まりますが、EBCDICについてはサポートされていません。そのため、ユーザー定義の照合順序を使用する必要があります。

https://www.ibm.com/docs/ja/db2/11.5?topic=sequences-simulation-ebcdic-binary-collation

ユーザー定義の照合順序を指定したCREATE DBを行うために、~/sqllib/samples/c/dbcreate.cがサンプルとして用意されているので、これを利用してEBCDIC照合順序を使用できるDBを作成してみます。
## ソースコードの作成
操作はDb2のインスタンスオーナーで行っています。~/sqllib/samples/c/dbcreate.cを適当なディレクトリーにコピーします。インスタンスオーナーでのCREATE DBだけをサポートできればよいので、ソースコードを改変します。
~~~dbcreate.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqle932b.h>
#include <sqlutil.h>
#include <sqlenv.h>

int DbCreate(char *, char *, char *);

int main(int argc, char *argv[])
{
  int rc = 0;
  char dbName[SQL_DBNAME_SZ + 1];
  char dbLocalAlias[SQL_ALIAS_SZ + 1];
  char dbPath[SQL_PATH_SZ + 1];

  switch(argc)
  {
    case 2:
      strcpy(dbName, argv[1]);
      strcpy(dbLocalAlias, "");
      strcpy(dbPath, "");
      break;
    case 3:
      strcpy(dbName, argv[1]);
      strcpy(dbLocalAlias, argv[2]);
      strcpy(dbPath, "");
      break;
    case 4:
      strcpy(dbName, argv[1]);
      strcpy(dbLocalAlias, argv[2]);
      strcpy(dbPath, argv[3]);
      break;
    default: 
      printf("Check usage.\n");
      return 1;
  }
  
  rc = DbCreate(dbName, dbLocalAlias, dbPath);

  return rc;
} /* main */

int DbCreate(char *dbName, char *dbLocalAlias, char *dbPath)
{
  struct sqlca sqlca;
  struct sqledbdesc dbDescriptor;
  SQLEDBTERRITORYINFO territoryInfo;

  strcpy(dbDescriptor.sqldbdid, SQLE_DBDESC_2);
  dbDescriptor.sqldbccp = 0;
  dbDescriptor.sqldbcss = SQL_CS_USER;
  memcpy(dbDescriptor.sqldbudc, sqle_932_5026, SQL_CS_SZ);
  strcpy(dbDescriptor.sqldbcmt, "EBCDIC ORDER DB");
  dbDescriptor.sqldbsgp = 0;
  dbDescriptor.sqldbnsg = 10;
  dbDescriptor.sqltsext = -1;
  dbDescriptor.sqlcatts = NULL;
  dbDescriptor.sqlusrts = NULL;
  dbDescriptor.sqltmpts = NULL;

  strcpy(territoryInfo.sqldbcodeset, "IBM-943");
  strcpy(territoryInfo.sqldblocale, "JP");

  sqlecrea(dbName,
           dbLocalAlias,
           dbPath,
           &dbDescriptor,
           &territoryInfo,
           '\0',
           NULL,
           &sqlca);

  printf("%s\n",sqlca.sqlstate);

  return sqlca.sqlcode;
} 
~~~
もとのソースコードにあったutilapi、utilembなどは今回の場合には必要ないので削除しました。次にMakefileを作成し、makeしてdbcreateモジュールを作成します。
~~~Makefile
CC		= gcc
CFLAGS	= -O4 -Wall -I/home/db2inst1/sqllib/include
LDFLAGS	= -Wl,-rpath,/home/db2inst1/sqllib/lib64 -L/home/db2inst1/sqllib/lib64
LIBS	= -ldb2
OBJ		= dbcreate.o
PROGRAM	= dbcreate
SRC		= dbcreate.c

all:			$(PROGRAM)

$(PROGRAM)	:	$(OBJ)
				$(CC) -o $(PROGRAM) $(OBJ) $(LDFLAGS) $(LIBS)

$(OBJ)		:	$(SRC)
				$(CC) -c $(SRC) $(CFLAGS)

clean:;         rm -f *.o *~ $(PROGRAM)
~~~
## DBの作成
作成したモジュールを実行し、list db directoryコマンドで作成できていることを確認します。
~~~
./dbcreate TESTEBC

db2 list db directory
Database 3 entry:

 Database alias                       = TESTEBC
 Database name                        = TESTEBC
 Local database directory             = /home/db2inst1
 Database release level               = 15.00
 Comment                              = EBCDIC order db2
 Directory entry type                 = Indirect
 Catalog database partition number    = 0
 Alternate server hostname            =
 Alternate server port number         =
~~~
## 照合順序の確認
db2 "select C from T order by C"で並び順を確認します。table Tについては適当に作成し、データも適当に入れました。
~~~
db2 "create table T (C char(1))"
db2 "select C from T order by C"
EBCDIC照合順序のテーブル ASCII照合順序のテーブル
C 　　　　　　　　　　　　C
- 　　　　　　　　　　　　-
+ 　　　　　　　　　　　　+
a 　　　　　　　　　　　　3
A 　　　　　　　　　　　　A
Z 　　　　　　　　　　　　Z
3 　　　　　　　　　　　　a
~~~
EBCIDIC照合順序のテーブルでは、数字が後ろになっている、英小文字がCAPS文字より前にきているなど、EBCDICの特徴を反映できました。
注意点としては、この方法は半角文字についてだけ適用できる方法で、DBCS文字については適用できません。多くの場合、並べ替えのキー項目は半角文字で作成されているので、事足りるのだと思います。