<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:admin="http://webns.net/mvcb/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>ハタさんのブログ(復刻版)</title>
<link>http://blog.xole.net/index.php</link>
<pubDate>Thu, 04 Jan 2007 04:57:55 </pubDate>
<description>
ハタさんのブログ(復刻版) - RSS 2.0 (Really Simple Syndication).
</description>
<item>
<title>PDOでpgsqlのbyteaカラムにはどうやって格納するの</title>
<link>http://blog.xole.net/article.php?id=536</link>
<pubDate>Thu, 04 Jan 2007 04:57:55 +09:00</pubDate>
<description>「PDOでpgsqlのbyteaカラムにはどうやって格納するの」という質問に詰まってしまったので、少し調べてみました。

bytea型なんてものを初めて聞いたのですが、マニュアルを覗いてみると「8.4. バイナリ列データ型」とありました...</description>
<content:encoded>
<![CDATA[<p>「PDOでpgsqlのbyteaカラムにはどうやって格納するの」という質問に詰まってしまったので、少し調べてみました。</p>

<p>bytea型なんてものを初めて聞いたのですが、マニュアルを覗いてみると「<a href="http://www.postgresql.jp/document/pg820doc/html/datatype-binary.html">8.4. バイナリ列データ型</a>」とありました。<br />
"バイナリ"とあるので、実際試していないながらもPDO::PARAM_LOBでいいんじゃね。と答えてみましたが、少し心配になったので<a href="http://viewcvs.php.net/viewvc.cgi/pecl/pdo_pgsql/pgsql_statement.c?revision=1.43&view=markup&pathrev=HEAD">pgsql_statement.c</a>を見てみると</p>

<pre>
<code>static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
{
	pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt-&gt;driver_data;
	struct pdo_column_data *cols = stmt-&gt;columns;
	
	if (!S-&gt;result) {
		return 0;
	}

	cols[colno].name = estrdup(PQfname(S-&gt;result, colno));
	cols[colno].namelen = strlen(cols[colno].name);
	cols[colno].maxlen = PQfsize(S-&gt;result, colno);
	cols[colno].precision = PQfmod(S-&gt;result, colno);
	S-&gt;cols[colno].pgsql_type = PQftype(S-&gt;result, colno);
	
	switch(S-&gt;cols[colno].pgsql_type) {

		case BOOLOID:
			cols[colno].param_type = PDO_PARAM_BOOL;
			break;

		case INT2OID:
		case INT4OID:
		case OIDOID:
			cols[colno].param_type = PDO_PARAM_INT;
			break;

		case INT8OID:
			if (sizeof(long)&gt;=8) {
				cols[colno].param_type = PDO_PARAM_INT;
			} else {
				cols[colno].param_type = PDO_PARAM_STR;
			}
			break;

		case BYTEAOID:
			cols[colno].param_type = PDO_PARAM_LOB;
			break;

		default:
			cols[colno].param_type = PDO_PARAM_STR;
	}

	return 1;
}</code>
</pre>

<p>というような記述があるので、たぶんLOBで大丈夫でしょう。(今度PDO::PARAM_LOBで試してみます)<br />
(ちなみに、<a href="http://www.postgresql.jp/document/pg820doc/html/libpq-exec.html#LIBPQ-EXEC-SELECT-INFO">PQftypeは問い合わせ関数</a>らしく、OIDを返すらしいです)</p>

<p>また、<a href="http://viewcvs.php.net/viewvc.cgi/pecl/pdo_mysql/mysql_statement.c?revision=1.59&view=markup&pathrev=HEAD">mysql_statement.c</a>はこんな感じ。</p>

<pre>
<code>static int pdo_mysql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
{
	pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt-&gt;driver_data;
	struct pdo_column_data *cols = stmt-&gt;columns;
	unsigned int i;

	if (!S-&gt;result) {
		return 0;	
	}

	if (colno &gt;= stmt-&gt;column_count) {
		/* error invalid column */
		return 0;
	}

	/* fetch all on demand, this seems easiest 
	** if we've been here before bail out 
	*/
	if (cols[0].name) {
		return 1;
	}
	for (i=0; i &lt; stmt-&gt;column_count; i++) {
		int namelen;
		namelen = strlen(S-&gt;fields[i].name);
		cols[i].precision = S-&gt;fields[i].decimals;
		cols[i].maxlen = S-&gt;fields[i].length;
		cols[i].namelen = namelen;
		cols[i].name = estrndup(S-&gt;fields[i].name, namelen);
		cols[i].param_type = PDO_PARAM_STR;
	}
	return 1;
}</code>
</pre>

<p>んで、このpgsql_stmt_describeやpdo_mysql_stmt_describeってのは何かというと、php_pdo_driver.hで定義されている構造体(インタフェース)で、こんな風に定義されてます。</p>

<pre>
<code>struct pdo_stmt_methods {
    pdo_stmt_dtor_func          dtor;
    pdo_stmt_execute_func       executer;
    pdo_stmt_fetch_func         fetcher;
    pdo_stmt_describe_col_func  describer;
    pdo_stmt_get_col_data_func  get_col;
    pdo_stmt_param_hook_func    param_hook;
    pdo_stmt_set_attr_func      set_attribute;
    pdo_stmt_get_attr_func      get_attribute;
    pdo_stmt_get_column_meta_func get_column_meta;
    pdo_stmt_next_rowset_func       next_rowset;
    pdo_stmt_cursor_closer_func     cursor_closer;
};</code>
</pre>

<p>ここで定義されているdescriberを通して色々なドライバがそのDBMSに合った型へ変換しているんですね(たぶん)。<br />
ちなみに、<a href="http://www.postgresql.jp/document/pg820doc/html/datatype.html">pgsqlは型が多い</a>のですが、<a href="http://viewcvs.php.net/viewvc.cgi/pecl/pdo_informix/informix_statement.c?revision=1.10&view=markup&pathrev=HEAD">infomixのinformix_statement.c</a>は結構迫力あります。</p>

<p>また、describerが発行されるタイミングとしては、<a href="http://jp2.php.net/manual/ja/function.pdostatement-getcolumnmeta.php">PDOStatement::getColumnMeta</a>の時っぽいです。(::executeのときも?)</p>

<p>といってもソースを眺めただけでトレースしてませんので、深い部分(?)は識者の方に任せつつ、今後じっくりこの辺を追ってみます。</p>

<p># それにしてもpgsqlの型は多すぎじゃないかしら</p>]]>
</content:encoded>
</item>
</channel>
</rss>