- ベストアンサー
データベース接続制御関数について
同じような質問を昨日したのですが、色々調べた上でちょっと質問内容が 的外れな感じだったので再質問します (前回の質問は後ほど削除しておきます) 現在行っている課題として以下の事を行っています。 ・C言語とDB(PostgreSQL)を使ったデータの移動 今まではLINUXのREDHATにTeratermでアクセスを行い、その中でC言語から CSVファイルのデータを取得、新しいファイル(CSVファイル)に書き出 し、という処理を行ってきました。 今回はこの最初に取得するCSVファイルの部分をDB(PostgreSQL)に置き 換え、同じ実行結果を得るというのが最終目的です。 昨日まではちょっと分からなかったのですが、日本PostgreSQLユーザ会の 日本語ドキュメントや以下のサイトを参考にして考えていたのですが… ファイヤープロジェクト http://www.fireproject.jp/feature/postgresql/programing_libpq/query_select.html 自分なりの解決方法として (1)何か実行結果を得たい (2)調べて、参考サイトとサンプルコードを見つける (3)当たり障りが無いようなら、サンプルコードを実行してみる (4)エラーが出ても実行結果が得られるまで、やってみる (5)出た結果から何がどう動いているか検証する とやってみたのですが、今回は上記のサイト(ファイヤープロジェクト libpqを使用したDBアクセスプログラミング)から持ってきたサンプルコードを gcc -Wall -I/usr/include/postgresql/ -lpq query2.c でコンパイルし生成された a.out よりコマンドで $> ./a.out 1024 "host=localhost user=Linux/Redhatの中で作ったユー ザー名 password=パスワード dbname=PostgreSQL内で作ったDB名" と打つと ### start connect 0 0 ### PQconnectdb OK ### end connect 0 0 ### ### start createTable 0 0 ### NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'hoge_pkey' for table 'hoge' ### end createTable 1 1 ### ### insert start 1 0 ### insert completed (1024/1024) ### end insert 7 6 ### ### start select 7 0 ### ########## SQL command status [SELECT] ########## 上記のような文が表示され (もしかしたら、少し違う所で記述が終わっていたかもしれません) column number 7113 is out of range 0..2 column number 7113 is out of range 0..2 column number 7113 is out of range 0..2 -1 (null) 0 のような文がとまらなくなり、Ctrl-Cで止めてみると、hogeというテーブ ルが出来ている状態です。 何も進まなかった昨日と比べれば、何か進んだ感もあるのですが、意味が 分からなくては勉強になりません。 ドキュメントやサイトの説明を理解し、サンプルコードを読み下すには もっとSQL文を理解しなくてはならないでしょうか? (私はPostgreSQLははじめたばかりで本を片手にインストール、設定、 ユーザー作成、データベース作成、ユーザー作成、テーブル作成、今まで のCSVファイルをテーブルにコピーの作業しかやっていません。) そしてやっている方向性は間違っていないでしょうか? できればこの課題の実行結果を得るためのヒントを頂ければ嬉しいです。 それでは宜しくお願い致します。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
なんかどっかで見たようなと……思ったら、前の続きでしたか。 初学者にはよくあることなんですが、エラーメッセージが出たら、 読んでください 今回の答えもそこにちゃんとあります。 (ものすごいオチだったりしますが……) > connect.c: 関数 `selectRecords' 内: > connect.c:359:6: 警告: コメント内に "/*" があります ココです。ソースを見てみましょう。 (スペースを全角に変えていますので注意) 359 /* フィールドインデクス,フィールド名/サイズの表示 */ メッセージは「コメント内に "/*" が」と言っていますが、 コメントはきちんと開始・終了しています。何ら問題はなさそうです。 でも警告が出ています。ということは、 それ以外の行がおかしい ことを疑う必要があります。 "/*" がコメントの中で出てきたと言っているのですから、 その手前のコメントがまだ終わっていないものと思われます。 ちょっと戻ってみましょう。 356 /* フィールド数 :/ 閉じてません(!) Shift キーを押し損ねたものと思われます。 したがって下記の部分全体がコメントとして解釈されます。 そして確かにコメントの中で "/*" が出てくることになるので 当該の警告が出たわけです。 356 /* フィールド数 :/ 357 fieldNum = PQnfields (result); 358 fprintf (stdout, "tuple has %d fields\n", fieldNum); 359 /* フィールドインデクス,フィールド名/サイズの表示 */ 引用元のページではわかりやすく色分け表示されていますが、 やはりこの部分全体がコメントとして解釈されて茶色くなってますね。 結果として変数 fieldNum には代入が行われません。 さらに宣言で初期値を与えていませんから、 どんな値が入っているかは不定です。 少なくともまともな値ではありません。 これが問題の原因です。
その他の回答 (3)
- sakusaker7
- ベストアンサー率62% (800/1280)
お役ご免のようなので退散しますがw デバッガを使うことを覚えておくべきだと思います。 サンプルプログラムのポカはわたしも見落としてしまいましたが コンパイル時のメッセージをきちんと見ればわかるという話はあるものの デバッガでステップ実行すればどこがおかしいかすぐにわかったでしょう。 人によってはデバッガでステップ実行して動きを把握しろとかいう 意見もありますし。
補足
回答ありがとうございます。 <お役ご免のようなので退散しますがw もうちょっとゆっくりしていって下さい。 デバッガのお話なんですが、Linuxでのデバッグ作業をやった事がありません。 今まではWindows環境だったので visual studio を使ってデバッグを行っていました。 まだ触ったばかりなのであまり難しい事は出来ませんが、デバッグからプログラムを走らせて、一行づつ実行していく事はやっていました。 それと同じ作業をLinuxでもできますか? というか、出来るんでしょうね。調べるとgdbデバッグというものが出てきたので… Linux上でプログラムをデバッグする時は皆さんgdbというものを使うのでしょうか? それとも何か違う方法が?
- THX1138
- ベストアンサー率51% (108/208)
> 変数に上手く代入が出来ず不定の値が入ってしまった、という事ですね。 入ってしまった、と言うよりは拾った箱の中に入っていた ゴミをそのまま使ってしまった形になります。 割り当てられた変数 fieldNum 用のメモリは初期化されないからです。 最初は0が入っていると思うかもしれませんが、 0を書き込む時間がもったいないのでメモリの確保しかしません。 したがって前にそこを使った誰かが入れた値がそのまま入ってます。 > あまり理解していない物を動かしていると > エラーメッセージの多さだけにやられてしまって、 > 気づきませんでした。今後注意します。 衝撃のオチ(笑)だっただけに脱力しているかもしれませんが、 実はサンプルがバグっていた、という例はしばしばあります。 Web サイトはともかく、書籍の場合は原稿から製本まで 途中にいろんな人の手が入りますから結構危険です。 書いてある通りにやってるのに動かないのは困りものですが、 対応を心得ていれば「あ、間違えてる」で終わりです。 今回の例でもそう断じるだけの根拠(エラーメッセージ)がありましたし、 実際そうでしたよね。 > (勉強なので自分で考えないと、とも思い)、 現状から察するに、libpq よりは C の基礎固めをした方がいいと思います。 トラブルさえ起きなければデキるのはわかりますが、 ひとたびコケたらお手上げ、という印象です。 ソフト開発というものは 絶対にコケる(涙) ので、耐性を付けないと生きていけません。 入門書を再度読み込んでください。 手始めに他に出ていた警告(型不一致の件)を退治してみてはどうでしょう。 > ※list[ii].○○ … 今までCSVファイルのデータを格納していた構造体 既にその流れができているのであれば 流用してしまっていいのではないでしょうか。 データ取り込み部分だけすりかえるイメージですかね。
補足
すばやい回答でとても助かります。 <入ってしまった、と言うよりは拾った箱の中に入っていた <ゴミをそのまま使ってしまった形になります。 そうですね。書き方が悪かったですね。 これは入ったのではなく、入っていたものを見たという形ですね。 <衝撃のオチ(笑)だっただけに脱力しているかもしれませんが、… 正直、本当に分からないままやっていたので「全然違う事を やっているんじゃないか?」という気持ちだっただけに、 むしろホッとした気持ちです。 サンプルなども間違っている事もあるという事を 頭に置いてやっていこうと思います。 <現状から察するに、libpq よりは C の基礎固めを した方がいいと思います。 最もだと思います。 しかしこれはあくまで仕事としての課題なので Cばかりやる訳にもいかず、 新しい事を出来るようになる事を目的としているので 課題を進めながらCを復習していく形になると思います。 なので今やってきたエラーメッセージなどは必ずまた 引っかかると思うので、 そこはもう一度間違わないよう、 同じ間違いをしない様にしていきたいと思います。 <ひとたびコケたらお手上げ、という印象です すいません、正直プログラミング自体は三ヶ月ほどの初心者なのでお手上げという状況がかなりあります。 しかし初心者だろうがなんだろうが、出来なければダメなのでこうして皆さんの手を借りながら進めている次第です。 <既にその流れができているのであれば <流用してしまっていいのではないでしょうか。 <データ取り込み部分だけすりかえるイメージですかね。 了解しました。 DB接続部分を関数化し、プログラム本体に組み込んでいこうと思います。 何度も教えていただきありがとうございました。 (また引っかかってしまうと思いますが…)
- sakusaker7
- ベストアンサー率62% (800/1280)
リンク先にあるサンプルプログラムをそのまま使ってますか? 止まらなくなるというメッセージの前に、 /* フィールド数 :/ fieldNum = PQnfields (result); fprintf (stdout, "tuple has %d fields\n", fieldNum); /* フィールドインデクス,フィールド名/サイズの表示 */ ここで出力している fieldNum の値が出力されていると思うんですが、 その値はどうなってますか? まあSQLの基本的なところ(文法とかコマンドとか)を抑えておかないと ちょっときついでしょうね。 とはいえそんなに難しいレベルはとりあえず必要ないはずなので、 簡単な問い合わせができるようであれば当面はいいだろうと思います。 for (i = 0; i < fieldNum; i++) { fprintf (stdout, "%d\t%s\t%d\n", PQfnumber (result, PQfname (result, i)), PQfname (result, i), PQfsize (result, i)); } ループの中の呼び出しでステータスをチェックして、何か異常があったら 即座にループを抜けるようにしたほうがいいでしょう。 たぶん、作成したデータベースにあるものよりとんでもなく大きな数字が fieldNum に入ってしまっていて、エラーが起きてもお構いなしにその回数だけ ループを回ろうとしているんじゃないかと思います。
補足
回答ありがとうございます。 早速、上記の事を確認しようと思い、再度 a.out を実行してみました。 すると… ### start connect 0 0 ### connect failed expected authentication request from server, but received S というエラーメッセージが出て動きません。 原因がよく分からないので(PostgreSQLサーバーは起動済み)、再起動というか teraterm なので再接続し、実行も上手く実行されず、 しょうがないのでもう一度 gcc からコンパイルしてみると今度はこっちも上手くいきません。 一応以前やった処理をメモに控えていたのですが、もしかしたら色々やって いたのでメモ自体がどこか違っていたのかもしれません。 ちなみにエラーメッセージはこんな感じです。 connect.c: 関数 `insertRecords' 内: connect.c:216: 警告: フォーマットは int ですが、引数は pointer です (引数 5) connect.c: 関数 `selectRecords' 内: connect.c:278: 警告: 変数 `tupleNum' は使われませんでした connect.c:359:6: 警告: コメント内に "/*" があります /tmp/ccUkaWMz.o(.text+0xfa): In function `main': : undefined reference to `PQfinish' /tmp/ccUkaWMz.o(.text+0x121): In function `connectToServer': : undefined reference to `PQconnectdb' /tmp/ccUkaWMz.o(.text+0x159): In function `connectToServer': : undefined reference to `PQstatus' /tmp/ccUkaWMz.o(.text+0x1af): In function `connectToServer': : undefined reference to `PQerrorMessage' /tmp/ccUkaWMz.o(.text+0x1cb): In function `connectToServer': : undefined reference to `PQfinish' /tmp/ccUkaWMz.o(.text+0x1f8): In function `connectToServer': : undefined reference to `PQfinish' /tmp/ccUkaWMz.o(.text+0x2ad): In function `createOrDropTable': : undefined reference to `PQexec' /tmp/ccUkaWMz.o(.text+0x2c7): In function `createOrDropTable': ~一部省略~ collect2: ld はステータス 1 で終了しました sakusaker7さんのアドバイスにもあったようにSQL文の文法をもう少しやらないと理解しづらいですね。 あとアドバイスの最後にあったループの~…という所は言っている事は理解できます。 というか持ってくるサンプルコード自体自分のニーズにあっていないもの何ではないかと思ってきました。 「ソース中にランダム関数が入っているのでどこかを自分で指定しないと 適当に何かがランダムに入ってエラーが起きるみたいな感じなのかなぁ」 と思いましたが、理解しない上での推測なので当てにはなりません。 これは追加で新しい質問なんですが、 (1)接続までは多分出来ていると思うのですが… 以下のサンプルコードが実行できている ※サンプルコード(PostgreSQLをプログラムで操作する) http://www.atmarkit.co.jp/flinux/rensai/postgres03/postgres03.html これは接続し、中を覗いて表示するという流れなんですが、ここからデータを新しいテーブルを作成し、 取得という形にするには、上記のサイトのソースにどういった物を追加していく事になるのでしょうか? この後本屋にでもいって、似たような事が載っている本を探してこようと思いますが、 もし時間がありましたらアドバイスお願い致します。
補足
回答ありがとうございます。 前回の続きで早くもつまずいてしまい、にっちもさっちもという感じで… 今回も分かりやすい回答で助かります。 なるほど!という感じですね。 コメントが上手くいかず、変数に上手く代入が出来ず不定の値が入ってしまった、という事ですね。 あまり理解していない物を動かしているとエラーメッセージの多さだけにやられてしまって、 気づきませんでした。今後注意します。 それで、前回は一段落ついたので一度質問を締め切ってしまったのですが (勉強なので自分で考えないと、とも思い)、 もうこれ以上時間を掛ける訳にもいかないので、ずばり質問します。 Q、このサンプルと前回のサンプル、私の得たい実行結果にするにはどっちが良いでしょうか? 自分では色々調べた結果。前回のサンプルをDB接続まで行った状態で list[ii].num = PQgetvalue(res,i,0); //項目1番目を取得 list[ii].san = PQgetvalue(res,i,1); //項目2番目を取得 list[ii].kok = PQgetvalue(res,i,2); //項目3番目を取得 ※list[ii].○○ … 今までCSVファイルのデータを格納していた構造体 と行っていき、データ格納関数(仮)として関数化。 そして今までのプログラム本体のデータを格納していた部分と入れ替え。 それを新しくファイルに書き込んでいくような流れなのかな? と思っているのですが… THX1138さんが説明不足やソースが無いと判断しかねる、といった場合は 私もあきらめて違う方法も考えていきたいと思います。 (全ソースは掲載しきれないので…) しかし出来れば、前回からとても効果的なTHX1138さんのアドバイスが欲しいと思っています。 もし、また時間がありましたらぜひアドバイス宜しくお願い致します。