PostgreSQL «курсор не расположен на строке» с драйвером ODB C - PullRequest
1 голос
/ 30 марта 2020

Я пытаюсь использовать на PostgreSQL 12.2 обновляемый курсор внутри транзакции, используя драйвер ODB C (ANSI 12.1) и C ++.

Если я объявляю курсор с помощью SQLSetCursorName и SQLPrepare + SQLExecute для запроса в одном операторе и для обновления в другом операторе он дает SQLSTATE 24000 и сообщение курсор "cur0" не расположен в строке .

Если обновление выполняется в тот же оператор, он дает SQLSTATE 24000 и сообщение Недопустимое состояние курсора .

В DSN, который я проверил Использовать Declare / Fetch , установите уровень отката при ошибках опция оператор и непроверенная обновляемые курсоры , следующие за https://www.microfocus.com/documentation/enterprise-developer/ed40pu15/ED-VS2015/GUID-1F1C4505-B771-4F8E-B274-952CAF3E8265.html.

Возможный способ был с SQLSetPos, но с использованием того же оператора для SELECT и UPDATE, как описано в http://micronetinternational.com/index.pl/en/00/https/www.postgresql-archive.org/ERROR-with-quot-Update-where-Current-of-quot-td4499184.html.

Используя DBeaver, который использует драйвер JDB C, он работает нормально.

Можно ли сделать т он обновляется с помощью другого оператора обновления для PostgreSQL с использованием драйвера ODB C?

  rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
  check_rc(henv, hdbc, hstmt, rc);

  rc = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);
  check_rc(henv, hdbc, hstmt, rc);

  rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
  check_rc(henv, hdbc, hstmt, rc);

  rc = lpfSqlConnect(hdbc, (SQLCHAR*)"mydsn", SQL_NTS, (SQLCHAR*)"user", SQL_NTS, (SQLCHAR*)"pass", SQL_NTS);
  check_rc(henv, hdbc, hstmt, rc);

  rc = SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_IS_INTEGER);
  check_rc(henv, hdbc, hstmt, rc);

  rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
  check_rc(henv, hdbc, hstmt, rc);

  rc = SQLSetStmtAttr(hstmt, SQL_ATTR_NOSCAN, (SQLPOINTER)SQL_NOSCAN_ON, SQL_IS_INTEGER);
  check_rc(henv, hdbc, hstmt, rc);

  rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (void *)SQL_CURSOR_KEYSET_DRIVEN, 0);
  check_rc(henv, hdbc, hstmt, rc);

  rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_ROWVER, 0);
  check_rc(henv, hdbc, hstmt, rc);

  rc = SQLSetCursorName(hstmt, (SQLCHAR *)"cur0", SQL_NTS);
  check_rc(henv, hdbc, hstmt, rc);

  rc = SQLPrepare(hstmt, (SQLCHAR *)"select field1, field2 from mytable", SQL_NTS);
  check_rc(henv, hdbc, hstmt, rc);

  rc = SQLExecute(hstmt);
  check_rc(henv, hdbc, hstmt, rc);

  SQLSMALLINT iNumCols = 0;
  rc = SQLNumResultCols(hstmt, &iNumCols);
  check_rc(henv, hdbc, hstmt, rc);

  for(i = 0; i < iNumCols; ++i)
  {
    rc = SQLBindCol(hstmt, i + 1, SQL_C_CHAR, data[i], collen[i], &outlen[i]);
    check_rc(henv, hdbc, hstmt, rc);
  }

  for (i = 0; i < 4; ++i)
  {
    rc = SQLFetch(hstmt);
    check_rc(henv, hdbc, hstmt, rc);
  }
//////////////////////////////////////////////////////////////////
  //it returns SQL_ERROR, SQLSTATE=24000, message "[Microsoft][ODBC Driver Manager] Invalid cursor state"
  rc = SQLExecDirect(hstmt, (SQLCHAR *)"UPDATE mytable SET field3 = 'newvalue' where current of cur0", SQL_NTS);
  check_rc(henv, hdbc, hstmt, rc);
/////////////////////////////////////////////////////////////////
  //or
  SQLHSTMT hstmt2 = SQL_NULL_HSTMT; // Statement Handle

  rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt2);
  check_rc(henv, hdbc, hstmt2, rc);

  rc = SQLSetStmtAttr(hstmt2, SQL_ATTR_RETRIEVE_DATA, (SQLPOINTER)SQL_RD_OFF, SQL_IS_INTEGER);
  check_rc(henv, hdbc, hstmt2, rc);

  //it returns SQL_ERROR, SQLSTATE=24000, message ERROR: cursor "cur0" is not positioned on a row;
  rc = SQLExecDirect(hstmt2, (SQLCHAR *)"UPDATE mytable SET field3 = 'newvalue' where current of cur0", SQL_NTS);
  check_rc(henv, hdbc, hstmt2, rc);
////////////////////////////////////////////////////////////

  rc = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);
  check_rc(henv, hdbc, NULL, rc);

  rc = SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_INTEGER);
  check_rc(henv, hdbc, hstmt, rc);

...