0

cにプログラムがあり、ユーザーに製品の製造元を入力するように求めます。ユーザーの入力に基づいてクエリを実行し、PC、ラップトップ、プリンターなど、その製造元が製造するすべての製品を印刷する必要があります。ただし、1つの行を返した後に2つのSQL状態を取得するため、ここで問題が発生します。

SQLSTATE-02000およびSQLSTATE=24000

これらはどちらも、私が検索したSQLエラーコードには含まれていません。

以下に、使用している.cファイルと.sqlスキーマを含めました。

どんな助けでも大歓迎です。

  #include <stdio.h>
  #include <stdlib.h>

  /*** header file for ORACLE definitions ***/
  exec sql include sqlca;

  int print_sql_state(char *code){
    printf("\nSQLSTATE=%s\n", code);
  }

  int main()
  {
    /*** Variable Declaration Block ***/
    exec sql begin declare section;
      char login[129], password[129];
      char SQLSTATE[6];

      /*query based on*/
      char maker[40];
      /*results based on product*/
          int model;
          char type[40];
      /*results based on type of product*/
          float speed;
          int ram;
      int hd;
      float screen;
      int price;
    exec sql end declare section;

    /*** handler for error ***/
    exec sql whenever sqlerror goto report_error; 
    exec sql whenever not found goto notfound;



    /*** Prompt user for login name and password ***/
    printf("Username=");
    gets(login);
    printf("Password=");
    char *pass_string = malloc(128);
    pass_string=getpass("");
    strcpy(password, pass_string);

    /*** Connect to DB ***/
    exec sql connect :login
       identified by :password;

    printf("\nCONNECTION SUCCESSFUL\n");

      /*** INSERT RECORD WITH VALUES PROVIDED BY USER ***/
    while(1){ 
      printf("\nInput manufacturer:");
      scanf("%s", &maker);
      if (maker==-1) /* end loop */
        return 0;

            /*** cursor declaration ***/
      exec sql declare specs_1 cursor for
          SELECT P.model, P.speed, P.ram, P.hd, P.price
          FROM Product PR, PC P
          WHERE PR.model = P.model AND PR.maker = :maker
          UNION
          SELECT L.model, L.speed, L.ram, L.hd, L.price
          FROM Product PR, Laptop L
          WHERE PR.model = L.model AND PR.maker = :maker;

          /*seperate query since not Union Compatible*/
      exec sql declare specs_2 cursor for
          SELECT P.model, P.price
          FROM Product PR, Printer P
          WHERE PR.model = P.model AND PR.maker = :maker;

        exec sql open specs_1;
        /*** TRAVERSE RESULT SET WITH CURSOR ***/
        while(1){ 
          EXEC SQL
          FETCH specs_1 into :model, :speed, :ram, :hd, :price;
          printf("\nModel = %d, Speed = %f, Ram = %d, hd = %d, Price = %d",
                           model, speed, ram, hd, price);
        }

        exec sql open specs_2;
        /*** TRAVERSE RESULT SET WITH CURSOR ***/
        while(1){ 
          EXEC SQL
          FETCH specs_2 into :model, :price;
          printf("\nModel = %d, Price = %d", model, price);
        }

          continue;
      exec sql close specs_1;
      exec sql close specs_2;

      notfound:
          printf("\nNO DATA");
          print_sql_state(SQLSTATE);
          exec sql close specs_1;
          exec sql close specs_2;
    }


    report_error:
        printf("\nCONNECTION ERROR\n");
        print_sql_state(SQLSTATE);
        return 1;           
  }

そしてSQL

  CREATE TABLE Product(
      maker VARCHAR(50),
      model INTEGER PRIMARY KEY,
      type VARCHAR(10) /*PC, Laptop, or Printer*/
      );

  CREATE TABLE PC(
      model INTEGER PRIMARY KEY, /*model number*/
      speed REAL,
      ram INTEGER,
      hd INTEGER,
      price INTEGER /*"in dollars"*/
      ;

  CREATE TABLE Laptop(
      model INTEGER PRIMARY KEY,
      speed REAL,
      ram INTEGER,
      hd INTEGER,
      price INTEGER,
      screen INTEGER
      );

  CREATE TABLE Printer(
      model INTEGER PRIMARY KEY, /*model number*/
      price INTEGER /*"in dollars"*/
      );

編集:::「メーカー」として「Dell」と入力したときのプログラムの出力

  Username=me
  Password=

  CONNECTION SUCCESSFUL

  Input manufacturer:Dell

  Model = 1, Speed = 3.400000, Ram = 4000, hd = 125, Price = 999
  NO DATA
  SQLSTATE=02000

  CONNECTION ERROR

  SQLSTATE=24000

編集::これらは私が使用しているテストインサートです。

  INSERT INTO Product Values('Alien', 5, 'PC');
  INSERT INTO PC Values(5, 3.0, 8000, 500, 1299);

  INSERT INTO Product Values('HP', 7, 'PC');
  INSERT INTO PC Values(7, 3.0, 8000, 500, 2899);

  INSERT INTO Product Values('Toshiba', 8, 'PC');
  INSERT INTO PC Values(8, .3, 1000, 20, 299, 10);

  INSERT INTO Product Values('Dell', 1, 'Laptop');
  INSERT INTO Laptop Values(1, 3.4, 4000, 125, 999, 13);

  INSERT INTO Product Values('Sony', 4, 'Laptop');
  INSERT INTO Laptop Values(4, 1.2, 2000, 20, 299, 10);

  INSERT INTO Product Values('HP', 2, 'Laptop');
  INSERT INTO PC Values(2, 1.0, 8000, 500, 899, 19);

  INSERT INTO Product Values('Toshiba', 9, 'Laptop');
  INSERT INTO Laptop Values(9, .4, 900, 20, 299, 10);

  INSERT INTO Product Values('Toshiba', 10, 'Laptop');
  INSERT INTO Laptop Values(10, .4, 900, 20, 299, 13);

  INSERT INTO Product Values('Toshiba', 11, 'Laptop');
  INSERT INTO Laptop Values(11, .4, 900, 20, 299, 10);

  INSERT INTO Product Values('Toshiba', 12, 'Laptop');
  INSERT INTO Laptop Values(12, .4, 900, 20, 299, 19);

  INSERT INTO Product Values('Dell', 3, 'Printer');
  INSERT INTO Printer Values(3, 199);

  INSERT INTO Product Values('Kodak', 6, 'Printer');
  INSERT INTO Printer Values(6, 300);
4

1 に答える 1

0

SQLエラーコードは、SQLSTATEではなくSQLCODEにあります。2000のSQLSTATEは、単に行がなくなったことを意味します。24000は、カーソルが無効な状態にあることを意味します。これは、カーソルを使い続けた場合に予想されることです。コードの外部からステートメントをチェックして、複数の行を取得していることを確認する必要があります。


そうは言っても、コードには疑わしいことがいくつかあります。1つ目は、パスワードに128バイトを割り当て、ポインタをの戻り値に設定してすぐにパスワードをリークすることですgetpass()maker == -12つ目は、ブレークが発生したときの外側のループの終了条件です。makerは文字配列であるため、-1になることはありません

また、プログラムの実際の出力を調べて(そして教えて)ください。これにより、問題が発生している場所に関する重要な手がかりが得られます。


そして、挿入ステートメントに基づいて、1行だけが取得されます。DellラップトップとDellプリンタを挿入しますが、最初のカーソルクエリはラップトップとPC(それぞれ1と0)のみを検索します。

したがって、2000(これ以上のデータはありません)がデータベースからの正しい応答です。

これで、2番目のクエリでプリンタを取得する必要があると思うかもしれませんが、実行されていれば取得できます。残念ながら、最初のクエリの「データがない」ため、2番目のクエリは完全にスキップされ、外側のループに戻ります。

プリンタビットを別のユニオンとして追加し、速度、RAM、およびHDサイズの定数を選択するだけで、これを単一のクエリとして実行できる可能性があります。もちろん、2つのタイプ(これらのフィールドがある場合とない場合)を区別するために、追加の列が必要になります。

または、各クエリに独自のエラー処理コードを指定して、最初のクエリが停止したときに2番目のコードがスキップされないようにすることもできます。

于 2012-11-19T08:27:31.207 に答える