src/SqlException.cpp
author František Kučera <franta-hg@frantovo.cz>
Thu, 04 Jun 2020 00:46:00 +0200
branchv_0
changeset 47 428c278af4be
parent 45 225e294ad1db
permissions -rw-r--r--
rename option --data-source-url to --data-source-string In some implementations like JDBC, the connection string is URL, but in ODBC the string is not formally URL, so it is better to use more general term „data source string“ instead of URL. - data source name (DSN) = name of a pre-configured database connection that should be looked-up in configuration and used - data source string (connection string) = arbitrary string containing (in certain encoding which might and might not be URL) all needed parameters (e.g. server name + port + user name + password) Name and string might sometimes be also combined: in ODBC we can e.g. connect to a string: DSN=relpipe;someParameter=foo;someOther=bar which will lookup configuration for the „relpipe“ data source and will combine it with given parameters.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
35
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     1
/**
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     2
 * Relational pipes
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     3
 * Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     4
 *
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     5
 * This program is free software: you can redistribute it and/or modify
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     6
 * it under the terms of the GNU General Public License as published by
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     7
 * the Free Software Foundation, version 3 of the License.
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     8
 *
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     9
 * This program is distributed in the hope that it will be useful,
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    12
 * GNU General Public License for more details.
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    13
 *
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    14
 * You should have received a copy of the GNU General Public License
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    16
 */
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    17
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    18
#include <cstring>
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    19
#include <codecvt>
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    20
#include <locale>
36
91cb012d779a use ODBC, avoid direct dependency on SQLite
František Kučera <franta-hg@frantovo.cz>
parents: 35
diff changeset
    21
#include <iostream>
35
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    22
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    23
#include <sql.h>
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    24
#include <sqlext.h>
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    25
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    26
#include "SqlException.h"
39
b4af13653313 improved exception handling: diagnostics of prepare statement error
František Kučera <franta-hg@frantovo.cz>
parents: 38
diff changeset
    27
#include "OdbcCommon.h"
35
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    28
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    29
namespace relpipe {
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    30
namespace tr {
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    31
namespace sql {
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    32
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    33
SqlException::SqlException(std::wstring message) : message(message) {
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    34
}
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    35
39
b4af13653313 improved exception handling: diagnostics of prepare statement error
František Kučera <franta-hg@frantovo.cz>
parents: 38
diff changeset
    36
SqlException::SqlException(std::wstring message, SQLRETURN resultCode, SQLSMALLINT handleType, SQLHANDLE handle, bool freeHandle) : message(message), resultCode(resultCode) {
45
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    37
	std::wstring_convert < std::codecvt_utf8<wchar_t>> convertor("", L"conversion failed"); // TODO: support also other encodings
35
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    38
	SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1];
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    39
	SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1];
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    40
	memset(buffer, 0, sizeof (buffer));
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    41
	memset(sqlstate, 0, sizeof (sqlstate));
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    42
	SQLINTEGER sqlcode;
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    43
	SQLSMALLINT length;
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    44
	for (SQLSMALLINT i = 1; SQLGetDiagRec(handleType, handle, i, sqlstate, &sqlcode, buffer, SQL_MAX_MESSAGE_LENGTH + 1, &length) == SQL_SUCCESS; i++) {
45
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    45
		std::wstring diagMessage = convertor.from_bytes((char*) buffer);
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    46
		if (diagMessage == L"conversion failed") {
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    47
			for (size_t i = 0; i < sizeof (buffer); i++) if (buffer[i] > 126 || buffer[i] == '\r') buffer[i] = '?'; // keep only ASCII characters and avoid CR which breaks the output
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    48
			diagMessage = convertor.from_bytes((char*) buffer);
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    49
		}
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    50
		diagnostics.push_back({convertor.from_bytes((char*) sqlstate), sqlcode, diagMessage});
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    51
		// FIXME: character encoding in SQLGetDiagRec()
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    52
		//
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    53
		// sometimes we get valid UTF-8 string
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    54
		// sometimes we get valid ISO-8859-1 string (which is not valid UTF-8)
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    55
		//
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    56
		// Temporary workaround: try UTF-8 decoding and if it fails, remove all non-ASCII characters and try again
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    57
		//
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    58
		// See also: DriverManager/SQLGetDiagRec.c:
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    59
		//   else if ( !__get_connection( head ) -> unicode_driver
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    60
		// and DriverManager/__info.c:
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    61
		//   char *asc[] = { "char", "char", "ISO8859-1", "ISO-8859-1", "8859-1", "iso8859_1", "ASCII", NULL };
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    62
		// in unixODBC
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    63
		//
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    64
		// We get valid UTF-8 if "PostgreSQL Unicode" driver is used and connection is successful: e.g. SELECT * FROM žádná_taková_tabulka_neexistuje;
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    65
		// We get valid ISO-8859-1 if "PostgreSQL Unicode" driver is used and connection is not successful and LANG=cs_CZ.UTF-8 e.g. [unixODBC]could not connect to server: Spojení odmítnuto
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    66
		// n.b. character í is present in ISO-8859-1, but other Czech characters (čřš etc.) are not (they are in ISO-8859-2)
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    67
		//
225e294ad1db faulty SQLGetDiagRec() call, unicode error, temporary workaround II
František Kučera <franta-hg@frantovo.cz>
parents: 44
diff changeset
    68
		// SQLGetDiagRec() behavior differs from other functions like SQLGetData(). Maybe use SQLGetDiagRecW() and decode UCS-2 / UTF-16.
44
ec9694f3b343 faulty SQLGetDiagRec() call, unicode error, temporary workaround
František Kučera <franta-hg@frantovo.cz>
parents: 39
diff changeset
    69
35
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    70
	}
39
b4af13653313 improved exception handling: diagnostics of prepare statement error
František Kučera <franta-hg@frantovo.cz>
parents: 38
diff changeset
    71
	if (freeHandle) OdbcCommon::freeHandle(handleType, handle);
35
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    72
}
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    73
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    74
std::vector<SqlException::SqlDiagnosticsRecord> SqlException::getDiagnostics() const {
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    75
	return diagnostics;
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    76
}
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    77
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    78
std::wstring SqlException::getMessage() const {
36
91cb012d779a use ODBC, avoid direct dependency on SQLite
František Kučera <franta-hg@frantovo.cz>
parents: 35
diff changeset
    79
	if (resultCode) return message + L" SQLRETURN=" + std::to_wstring(resultCode);
91cb012d779a use ODBC, avoid direct dependency on SQLite
František Kučera <franta-hg@frantovo.cz>
parents: 35
diff changeset
    80
	else return message;
35
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    81
}
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    82
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    83
SQLRETURN SqlException::getResultCode() const {
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    84
	return resultCode;
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    85
}
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    86
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    87
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    88
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    89
}
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    90
}
cd9db43db120 SqlException: ODBC diagnostics
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    91
}