DB2

2010年3月 2日 (火)

データ型のマップの続き

以前に、DB2というよりODBCのSQLデータ型やCデータ型にまつわるあれこれ(憂鬱)について色々書いたが、

各DBMSのデータ型がどのようにODBCのSQLデータ型にマップされるか調べてみたdashdash。ちなみに、ODBCでは「ドライバ」毎の独自のSQLデータ型を定義する事を認めている(その場合、どっかに申請しないといけない。つまり、値が衝突しない)。また、「ドライバ」毎と強調したのは、例えば、DB2用のODBCドライバといってもIBM純正のドライバの他にサードパーティ用のドライバがあったりするので注意。

まずは、DB2 Ver 09.07.0000。ドライバはIBM純正のDB2CLI.DLL Ver 09.07.0000。

DB2
DBMSのデータ型 ODBCのSQLデータ型
SMALLINT SQL_SMALLINT
INTEGER SQL_INTEGER
BIGINT SQL_BIGINT
DECIMAL SQL_DECIMAL
REAL SQL_REAL
DOUBLE SQL_DOUBLE
DECFLOAT *SQL_DECFLOAT(-360)
CHAR(FOR BIT DATA) SQL_CHAR(SQL_BINARY)
VARCHAR(FOR BIT DATA) SQL_VARCHAR(SQL_VARBINARY)
LONG VARCHAR(FOR BIT DATA) SQL_LONGVARCHAR(SQL_LONGVARBINARY)
CLOB *SQL_CLOB(-99)
GRAPHIC *SQL_GRAPHIC(-95)
VARGRAPHIC *SQL_VARGRAPHIC(-96)
LONG VARGRAPHIC *SQL_LONGVARGRAPHIC(-97)
DBCLOB *SQL_DBCLOB(-350)
BLOB *SQL_BLOB(-98)
DATE SQL_TYPE_DATE
TIME SQL_TYPE_TIME
TIMESTAMP SQL_TYPE_TIMESTAMP
DATALINK *SQL_DATALINK(-450)
XML *SQL_XML(-370)
UDT *SQL_USER_DEFINED_TYPE(-450)

以後、*はドライバ独自のSQLデータ型を表す。

CHAR、VAR CHAR、LONG VARCHARはFOR BIT DATAオプションを付けるとバイナリ型にマップされる。

次はPostgreSQL Ver 8.3.9。ドライバはPSQLODBC35W.DLL Ver 08.04.0100。

PostgreSQL
DBMSのデータ型 ODBCのSQLデータ型
smallint SQL_SMALLINT
integer SQL_INTEGER
bigint SQL_BIGINT
numeric SQL_NUMERIC
real SQL_REAL
double precision SQL_FLOAT
serial SQL_INTEGER
bigserial SQL_BIGINT
money SQL_FLOAT
"char" SQL_WCHAR
character SQL_WCHAR
character varying SQL_WVARCHAR
text SQL_WLONGVARCHAR
bytea SQL_VARBINARY
timestamp with time zone SQL_TYPE_TIMESTAMP
timestamp without time zone SQL_TYPE_TIMESTAMP
date SQL_TYPE_DATE
time with time zone SQL_WVARHCAR
time without time zone SQL_TYPE_TIME
interval SQL_WVARCHAR
boolean SQL_WVARCHAR
point SQL_WVARCHAR
line SQL_WVARCHAR
lseg SQL_WVARCHAR
box SQL_WVARCHAR
path SQL_WVARCHAR
polygon SQL_WVARCHAR
circle SQL_WVARCHAR
cidr SQL_WVARCHAR
inet SQL_WVARCHAR
macaddr SQL_WVARCHAR
bit SQL_WVARCHAR
bit varying SQL_WVARCHAR
xml SQL_WLONGVARCHAR
uuid SQL_GUID
tsvector SQL_WVARCHAR
tsquery SQL_WVARCHAR
array SQL_WVARCHAR

独自のSQLデータ型は全く定義しておらず、ODBC標準のSQLデータ型にないデータ型はSQL_WVARCHARなどにマップしてるっぽい。どうりで、ヘッダファイルが見つからなかったわけだ・・?。

次はSQL Server 2008 Ver 10.00.1600。ドライバはMS純正のNative Clientのsqlncli10.dll Ver 10.00.1600。

SQL Server
DBMSのデータ型 ODBCのSQLデータ型
tinyint SQL_TINYINT
smallint SQL_SMALLINT
int SQL_INTEGER
bigint SQL_BIGINT
decimal SQL_DECIMAL
smallmoney SQL_DECIMAL
money SQL_DECIMAL
bit SQL_BIT
real SQL_REAL
float SQL_FLOAT
char SQL_CHAR
varchar SQL_VARCHAR
text SQL_LONGVARCHAR
nchar SQL_WCHAR
nvarchar SQL_WVARCHAR
ntext SQL_WLONGVARCHAR
binary SQL_BINARY
varbinary SQL_VARBINARY
image SQL_LONGVARBINARY
date SQL_TYPE_DATE
time *SQL_SS_TIME2(-154)
smalldatetime SQL_TYPE_TIMESTAMP
datetime SQL_TYPE_TIMESTAMP
datetime2 SQL_TYPE_TIMESTAMP
datetimeoffset *SQL_SS_TIMESTAMPOFFSET(-155)
cursor ?
timestamp SQL_BINARY
hierarchyid *SQL_SS_UDT(-151)
uniqueidentifier SQL_GUID
sql_variant *SQL_SS_VARIANT(-150)
xml *SQL_SS_XML(-152)
table *SQL_SS_TABLE(-153)
udt *SQL_SS_UDT(-151)

と、ざっと見る限り、独自のSQLデータ型の値は衝突してないし。なるへそ。

ちなみに、これらマッピングは設定で変えられたり、データベースの文字コードによって、変わるかもしれないので・・

また、Cデータ型については独自のCデータ型を認めていないと書いてあるんだが、DB2やSQL Serverの独自のSQLデータ型に対応する独自のCデータ型がそれぞれ定義されているdashdash。独自のCデータ型を定義できるようになったのは最新のODBC 3.8 かららしいが・・

後はOracleとMySQLとFirebirdぐらいは調べたいんだが、いずれ気が向いたらインストールして調べるかdash


2009年9月24日 (木)

ODBCヘッダー

また、さぼってたwobbly。なんというかプログラミングに対する情熱?自体が最近なくなってきたwobbly。要するに作りたいものがなくなってきた。

そんな事はさておき、今回は以前やりかけの事がたくさんあると書いたが、その内のとりあえず公開できそうな物を公開してみる。ということで、今回はODBC(Open DataBase Connectivity)のDelphi用ヘッダーファイル。Cのヘッダーファイルを以前に頑張って移植したbearing

まぁ、今更ODBC?みたいな感があるが・・・Unicodeに対応するDelphi2009以前のDelphi用ですのであしからず。また、ODBCの関数を使う時は現状、LoadLibraryで自分でDLLをロードして下さいsad。ダウンロードはSkyDrive から。

本当はODBCのコンポーネントを作っていたのだが、まだ、公開できる状態ではないので、ヘッダーファイルだけでも・・・

ところでDelphiの最新版であるDelphi 2010が発売されたのであるが、Unicodeアプリを作れる環境がほしいので久しぶりに購入しようかなと思ってたり。でも、作りたいものがなくなってきたこともあり悩んでます。

2009年8月23日 (日)

間隔(インターバル)型の続き

以前の続きであるが、今回は間隔型のODBCでの対応について。

ODBCではSQL92の間隔型に相当するデータ型が定義されていて、そのSQLデータ型は次のようになる。

年月間隔

  • SQL_INTERVAL_YEAR
  • SQL_INTERVAL_MONTH
  • SQL_INTERVAL_YEAR_TO_MONTH

日時間隔

  • SQL_INTERVAL_DAY
  • SQL_INTERVAL_HOUR
  • SQL_INTERVAL_MINUTE
  • SQL_INTERVAL_SECOND
  • SQL_INTERVAL_DAY_TO_HOUR
  • SQL_INTERVAL_DAY_TO_MINUTE
  • SQL_INTERVAL_DAY_TO_SECOND
  • SQL_INTERVAL_HOUR_TO_MINUTE
  • SQL_INTERVAL_HOUR_TO_SECOND
  • SQL_INTERVAL_MINUTE_TO_SECOND

これら間隔型のデータをアプリケーションから入出力する時に、Cデータ型のSQL_C_CHARにマップつまり文字列として入出力してもよいのだが、間隔型専用のSQL_C_INTERVALの接頭辞で始まるCデータ型(SQL_C_INTERVAL_YEAR等)にマップして入出力することもできる。SQL_C_INTERVALの接頭辞で始まるCデータ型はSQL_INTERVAL_STRUCT構造体として定義され、次のようになっている。

まぁ、ここらへんはODBCのドキュメントに書いてあるので・・

ここでは、ちょっとWindowsのお話でも。.NET Frameworkでは間隔を扱うTimeSpan構造体というものが定義されているが、WindowsのネイティブAPIで間隔を扱うAPIなんてものがあるのかな?と前から思っていたら偶然発見したbearing

まずは、

間隔を文字列表現に変化するAPIであるが、実際に使って10万ミリ秒を変換してみた。

Interval2_1

このAPIはShell Lightwight Utility Functionsと呼ばれるAPIで将来のWindowsでは変更または利用不可になるかもしれないとの事・・・エクスプローラでファイルをコピーすると残りXX秒とかダイアログに表示されるが、そこで使われているのだろうか??

次は、Vistaで追加された

こちらも文字列表現に変換するAPIであるが、StrFromTimeIntervalと違いロケールや書式を指定できるとの事。これに合わせて、GetLocaleInfoなどでロケールに関する様々な情報を取得・設定できるが、間隔用のフォーマットのLOCALE_SDURATION定数が追加されている。Vistaもってないのでこららを試すことできないが・・・

2009年8月 8日 (土)

間隔(インターバル)型

ちょっと、データベースのデータ型のお話。

SQL92では2つの日時の差つまり期間を表すデータ型として間隔(インターバル)型が定義されているが、これらは次の2つに分類される。

  • 年月間隔(year-month間隔)
  • 日時間隔(day-time間隔)

年月間隔とは2つの日時の差を年、月で表すデータ型で例えば、「123年4ヶ月」、「48ヶ月」は年月間隔である。同様に、日時間隔は2つの日時の差を日、時、分、秒で表すデータ型で、「235日」、「64時間23分12秒」などは日時間隔である。Oracleでは年月間隔の間隔型としてINTERVAL YEAR TO MONTH型、日時間隔の間隔型としてINTERVAL DAY TO SECOND型が用意されている。DB2には残念ながら間隔型は用意されていない。

と、これら間隔型を理解するのはそう難しくないと思うが、1点注意する事がある。それは、年月間隔に属する間隔型と日時間隔に属する間隔型には互換性がないのが基本?である。つまり、年月間隔に属する間隔型と日時間隔に属する間隔型を比較したり、相互に変換できないのである。一見すると

年月間隔の「123年4ヶ月」>日時間隔の「36ヶ月」

のように比較したり、

年月間隔の「1年」->日時間隔の「365日」

のように変換できそうだが、できないのである。

なぜできないのかは、少し考えてみれば分かるように、月によって日数(28,29,30,31日)が変わったり、平年とうるう年では日数が違うからである。つまり、年月間隔の「1ヶ月」といっても1月なら31日あるし、平年の2月なら29日あるし、日時間隔の日数に変換しようとしても決定できないのである。

と当たり前の事を書いてみる。

最後に実際にOracleで年月間隔と日時間隔の間隔を比較してみる。

Interval1_1

月によって日数が変わるといっても、年月間隔の「12年」と日時間隔の「36日」じゃどう転んでも、「12年」の方が長いのであるが、年月間隔と日時間隔は互換性がないのでエラーになるのである。

2008年6月 7日 (土)

数値型の憂鬱(2)

前回の続きである。

高精度の数値の演算つまり多倍長演算のルーチンを自作するのもいいのだが、なるべくなら既存の信頼におけるものを使いたいものである。Googleなどの検索サイトで多倍長演算ライブラリを検索すれば、様々なライブラリが見つかり、開発環境の言語に合わせて選択できるが、WindowsのOS自体に用意されているライブラリを使う事もできる。

正確に言うと、WindowsのOS自体というより、WindowsのOLEオートメーションで主に使われるバリアントのために用意されているライブラリで、oleaut32.dll

  • VarDecAdd(加算)
  • VarDecSub(減算)
  • VarDecMul(乗算)
  • VarDecDiv(除算)
  • VarDecAbs(絶対値)
  • VarDecFix
  • VarDecInt
  • VarDecRound
  • VarDecNeg
  • VarDecCmp(比較)

などのAPIを使って多倍長演算を行うことができる。これらのAPIは、主に、DECIMAL構造体へのポインタを引数に取り、DECIMAL構造体は次のように宣言されている。

Numeric2_1_3 

wReservedフィールドはバリアントに格納されているデータの型を表し、Decimal型の場合、vt_decimal(14)、scaleフィールドは小数点の位置を表し、signフィールドを符号を表し、hi32、low32、mid32フィールドにスケーリングされた数値が整数値として格納される。

これとODBCを組み合わせてもよいのだが、上述のDecimal構造体のスケーリングされた整数値を格納する領域が96ビットなので、2の96乗つまり最大精度28桁までの数値しか表現できないwobbly。28桁だと最大精度38桁のOracleのNUMBER型はもとよりDB2のNUMBER型すら完全に表現できない・・・

んー。OSで多倍長演算ももっとサポートしてほしいのだが・・あまり、そのような要望はないのだろうか?

2008年6月 6日 (金)

数値型の憂鬱

今回は数値型の憂鬱である。

たいていのデータベースには、高精度の数値を表すデータ型が用意されている。DB2で言えば、DECIMAL/NUMERIC型で、最大精度31桁の巨大な数値を表現することができる。何が憂鬱かというと、これら高精度の数値をクライアント・アプリケーションで入出力するだけなら、高精度の数値を文字列として入出力すれば楽であるが、クライアント・アプリケーションでこられの数値を演算したり比較したりするとなると、途端に面倒になるのである。

というのも、たいていのクライアント・アプリケーションの開発環境では、このような高精度の数値を表現するデータ型がデフォルトで用意されていないからである(JavaならBigIntegerBigDecimalクラス、.NETならDecimal型が用意されているが・・)。

ちなみに、ODBCではこれら高精度の数値を表現するCデータ型としてSQL_C_NUMERICが用意されていて、SQL_NUMERIC_STRUCT構造体として入出力することもできる。SQL_NUMERIC_STRUCT構造体は次のようになる。

Numeric1_3   

precisionフィールドは有効桁数、scaleフィールドは小数点の位置、signフィールドは符号を表し、valフィールドにはスケールされた数値(整数値として)が格納される。ちなみに、valフィールドは16バイト長なので、2の128(16*8)乗つまり最大精度約38桁までの数値を表現できることになる。

と、高精度の数値を表すCデータ型が用意されているのであるが、加減乗除などの演算や比較を行うためのルーチンが用意されていないので、自前で用意するなどしなければならず頭が痛いのであるsad。ちなみに、SQL_NUMBER_STRUCTの使い方はここ

2008年5月17日 (土)

文字列型の憂鬱(3)

前回、データベースの文字コードとクライアントアプリケーションの文字コードが異なると文字コードの変換が発生し、文字列データの長さが拡張または縮小する可能性があるので、切り捨てが発生しないように必要なバッファ量を見積もるのが多少面倒であることを書いたが、そのような事を考える必要なしに文字列データを取得する方法がある。

SQLGetData関数を使う方法である。

SQLGetData関数は通常、長いデータと呼ばれるSQL_LONGVARCHARやSQL_LONGVARBINARYのSQLデータ型のデータを分けて取り出すために使われる(SQL_INTEGERやSQL_TYPE_TIMESTAMP等の固定長データもこの関数を使って取り出すことができるが、分けて取り出す事はできない)が、この関数を使い長いデータを取り出す時と同様に、SQLGetData関数がSQL_SUCCESSを返すまで複数回呼び出して取り出せば、取り出したデータを組み立てる必要はあるが、文字列データの拡張や縮小といった問題を考える必要なく取り出すことができる。

と、この関数を使ってデータを取り出す方が楽に思えるが、SQLGetData関数を使って取り出す列は通常は、SQLBindCol関数でバインドしてはならず、また、列番号の小さい列から大きい列に向かって、つまり、昇順に取り出さなければいけない等の制限があり、別の問題が発生するのである。頭痛い・・wobblyちなみに、どのような制限が課せられるかは、ドライバ次第で、この情報はSQLGetInfo関数(InfoType=SQL_GET_DATA_EXTENSIONS)で取得できる。

2008年5月15日 (木)

文字列型の憂鬱(2)

以前の文字列型の憂鬱の続きである。

文字列型の憂鬱では、文字列型と言うより、可変長データ型(文字列型やバイナリ型)の悩ましさ?を書いたが、バイナリ型ではない可変長データ型の文字列型のデータの送受信には、更に悩ましいことがある。

例えば、DB2でCHARACTER(6)として宣言された列は、SQLデータ型としてSQL_CHARとして報告される。SQLDescribeColまたはSQLColAttributes関数で列のサイズを問い合わせると、6が返されるので、データの切り捨てが発生しないように取り出すには7バイトのバッファを割り当れば良いように思える(+1バイトはNULL終端文字の領域で基本的にCLI/ODBCでSQL_C_CHARなどの文字列のCデータ型にマップする場合はNULL終端文字の領域が必要)。

が、話はこう単純ではないのである。

というのもDB2に限った話ではないが、データベースの文字コード(DB2で言えば、データベース・コードページ)とクライアントアプリケーションの文字コード(同じくアプリケーション・コードページ)が異なると通常、データベースによって文字コードの変換が行なわれ、文字列データのバイト長が縮小または拡張する可能性があるからである。

例えば、データベースの文字コードがShiftJISでアプリケーションの文字コードがEUC-JPの場合、全角文字の「あいう」はデータベースの文字コードShiftJISでは6バイト長(2バイト文字*3文字)であるが、アプリケーション側でデータを取り出すとEUC-JPの9バイト長(3バイト文字*3文字)に拡張するのである。よって、7バイトのバッファしか割り当ててないと切り捨てが発生するのである。要するに、SQLDescribeColまたはSQLColAttributes関数で返されるサイズとはあくまでもデータベースの文字コードにおけるサイズなのである。

と切り捨てが発生しないように文字列型のデータに必要な最大バッファ量を見積もるのは面倒なのである。

ちなみに、DB2 CLIでは、上記の問題に対し、専用のSQLGetSQLCAという関数を使って、文字列データの送受信時に、どれくらいの拡張または縮小する可能性があるかを示す拡張係数(Expansion Factor)というものを取得でき、これを使って、最大バッファ量を簡単に見積もれるようになっている。例えば、拡張係数が2であれば、最大でデータ長が2倍に拡大する可能性があるので、

(SQLDescribeColで返されるサイズ + 1)*2(拡張係数)バイト

のバッファを割り当てればよいことになる。また、SQLGetSQLCAでアプリケーション・コードページやデータベース・コードページも取得できる(SQLGetInfoでも取得できる)が、それらのコードページからクライアントアプリケーションでどれくらい拡張・縮小するかを見積もれないこともないが、面倒なので素直に拡張係数を使った方が無難である。

文字列って本当にめんどいsad

2007年11月16日 (金)

SQLGetInfo

今回はDB2 CLI/ODBCのSQLGetInfo関数である。ODBCは接続先のデータベースの種類によらない汎用的なアプリケーション・プログラミング・インターフェースを開発者に提供するために開発されたインターフェースであるので、実際の接続先のデータソースやドライバに関する情報を返す関数が用意されている。それが、SQLGetInfo関数である。

SQLGetInfo関数の呼び出し時に第2引数として指定するパラメータ(InfoType)の値により様々な情報が取得できる。指定できる値に例えば、次のようなものがある。

  • SQL_DATABASE_NAME
  • SQL_DBMS_NAME
  • SQL_DBMS_VER

  • SQL_TXN_CAPABLE
  • SQL_DEFAULT_TXN_ISOLATION
  • SQL_TXN_ISOLATION_OPTION
  • SQL_SCROLL_OPTIONS
  • SQL_CURSOR_COMMIT_BEHAVIOUR
  • SQL_CURSOR_ROLLBACK_BEHAVIOUR

上記は用意されている値のほんの一部である。最初の3つはDBMS Prodcut Informationと呼ばれる値で、SQL_DATABASE_NAMEは接続中のデータベースの名前、SQL_DBMS_NAMEは接続中のデータベース管理システムの名前、SQL_DBMS_VERはそのバージョンを表す情報を返す。

残りは、Data Source Informationと呼ばれる値で、SQL_TXN_CAPABLEはトランザクションの能力、SQL_DEFAULT_TXN_ISOLATIONはデフォルトのトランザクションの分離レベル、SQL_TXN_ISOLATION_OPTIONはサポートしているトランザクションの分離レベル、SQL_SCROLL_OPTIONSはサポートしているカーソルの種類(前方専用、静的、キーセット駆動、動的カーソルなど)を、SQL_CURSOR_COMMIT_BEHAVIOUR、SQL_CURSOR_ROLLBACK_BEHAVIOURは、トランザクションのコミットまたはロールバック時に、既存のオープン中のカーソルがどう振舞うかを表す情報を返す。

で、実際にDB2 Express CのSAMPLEデータベースに接続して上記の値を指定して情報を取得してみた。

Sqlgetinfo_2 

上のイメージより、サポートしている分離レベルはREAD UNCOMITTED、READ COMMITTED、REPETABLE READ、SERIALIZABLEのすべて、サポートしているカーソルの種類は前方専用、静的、キーセット駆動の3つ。また、SQL_CURSOR_COMMIT_BEHAVIOURのSQL_SC_PRESERVEは、トランザクションのコミット時にオープン中のカーソルが保存され、コミット後も引き続きフェッチできることを表す。同様に、SQL_CURSOR_ROLLBACK_BEHAVIOURのSQL_CB_CLOSEはロールバック時には、オープン中のカーソルが閉じられることを表す。前後するが、SQL_TXN_CAPABLEのSQL_TC_ALLはトランザクションにDML文のみならず、DDL文を含むことができることを表す(DB2はDDL文含むことできる??)。

と、様々な情報が取得できる。

2007年10月21日 (日)

そしてLOB型

で、実際にLOB型をLOBロケータ経由で取り出してみたがはまった。DB2 CLI独自の関数

  • SQLGetLength
  • SQLGetSubString

を使ってLOBを操作するのだが、LOBの実際のサイズを求めるSQLGetLength関数を呼び出すと何故かエラーが戻される。試しにサイズを求めず直接SQLGetSubString関数を呼び出しデータを取り出そうとしても同じエラーが戻される。戻されるエラーは

[IBM][CLI Driver]CLI0125E 関数のシーケンス・エラーです。SQLSTATE=HY010

である。関数の呼び出し順序がおかしいことを示すエラーである。色々調べても何がおかしいのか分からない。で、DB2 CLIのトレース機能を利用してトレースを取ってみた。トレース機能を有効にするには、DB2 CLIの初期化ファイルであるdb2cli.iniの[common]セクションにTrace=1というエントリを追加する(必要に応じてTraceFileNameなども追加)。取得できたトレースはこんな感じ。

Lobtrace_2 

述べたようにSQLGetLengthでエラー(SQL_ERROR)が戻されているのが分かる。ちなみに、SAMPLEデータベースのCLOB型のRESUME列を持つEMP_RESUME表を問い合わせている。また、上のログからも分かるように、RESUME列をSQL_C_CLOB_LOCATORとしてマップしてることも分かる。で、遊んだり再び調べたりすること数時間後、初めからそうしてればよかったのだが、DB2と共にインストールされたLOB列を読み書きするサンプルdtlob.cを見て、あれ。なんで文ハンドルを3つ用意してるんだ・・

理由はさておき、サンプルと同じように文ハンドルを3つ用意して実行したら、動いた・・修正前のプログラムでは、EMP_RESUME表をSELECTする文ハンドルをそのままSQLGetLength関数の引数に渡していたが、これがまずかったようである。新たに、新規の文ハンドルを割り当て、それを渡したら動くようになった。確かに、DB2 CLIのSQLGetLength関数に渡す文ハンドルの説明で、

「このステートメント・ハンドルは、準備済みステートメントまたはカタログ関数呼び出しに関連付けられててはいけません。」

とあったが、よく理解できていなった。確かに、シーケンスエラーだと。

ということで、LOBロケータを使ってLOBデータを取得するよう開発中のプログラムを修正した。

Readlob

RESUME列はCLOB(5120)として定義されている列で通常の文字列つまりCデータ型のSQL_C_CHARとしてマップすると、実際のデータのサイズに関わらず、データの切り捨てを防ぐためには、5120バイト以上のメモリを確保しなければいけないが、SQL_C_CLOB_LOCATORとしてマップしたことにより、取り出す時に実際のデータのサイズ分だけのメモリ確保すればよいことになる。

より以前の記事一覧

自作ソフトウェア

無料ブログはココログ

メモ