提交 9abd0554 编写于 作者: H Hiroshi Inoue

1) Fix SQLForeignKeys() in multibyte mode.

2) Fix a bug with NUMERIC scale in case of Parse
  statement option.
3) Remove a no longer needed loop in CC_send_query().

Hiroshi Inoue
上级 531126c8
......@@ -14,6 +14,10 @@
*/
/* Multibyte support Eiji Tokuya 2001-03-15 */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "connection.h"
#include "environ.h"
......@@ -27,9 +31,6 @@
#include "multibyte.h"
#endif
#include <stdio.h>
#include <string.h>
#ifdef WIN32
#include <odbcinst.h>
#endif
......@@ -277,6 +278,10 @@ memcpy(&(rv->connInfo.drivers), &globals, sizeof(globals));
rv->pg_version_number = .0;
rv->pg_version_major = 0;
rv->pg_version_minor = 0;
#ifdef MULTIBYTE
rv->client_encoding = NULL;
rv->server_encoding = NULL;
#endif /* MULTIBYTE */
/* Initialize statement options to defaults */
......@@ -302,6 +307,12 @@ CC_Destructor(ConnectionClass *self)
mylog("after CC_Cleanup\n");
#ifdef MULTIBYTE
if (self->client_encoding)
free(self->client_encoding);
if (self->server_encoding)
free(self->server_encoding);
#endif /* MULTIBYTE */
/* Free up statement holders */
if (self->stmts)
{
......@@ -510,6 +521,9 @@ CC_connect(ConnectionClass *self, char do_password)
char msgbuffer[ERROR_MSG_LENGTH];
char salt[5];
static char *func = "CC_connect";
#ifdef MULTIBYTE
char *encoding;
#endif /* MULTIBYTE */
mylog("%s: entering...\n", func);
......@@ -537,7 +551,9 @@ CC_connect(ConnectionClass *self, char do_password)
ci->drivers.bools_as_char);
#ifdef MULTIBYTE
check_client_encoding(ci->drivers.conn_settings);
encoding = check_client_encoding(ci->drivers.conn_settings);
if (encoding && strcmp(encoding, "OTHER"))
self->client_encoding = strdup(encoding);
qlog(" extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n",
ci->drivers.extra_systable_prefixes,
ci->drivers.conn_settings,
......@@ -1041,7 +1057,6 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
CC_set_no_trans(self);
ReadyToReturn = TRUE;
retres = NULL;
break;
}
else
{
......@@ -1059,6 +1074,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
QR_set_status(res, PGRES_COMMAND_OK);
QR_set_command(res, cmdbuffer);
query_completed = TRUE;
mylog("send_query: returning res = %u\n", res);
if (!before_64)
break;
/*
......@@ -1069,71 +1085,14 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
* an 'I' is received
*/
if (empty_reqs == 0)
{
SOCK_put_string(sock, "Q ");
SOCK_flush_output(sock);
empty_reqs++;
}
break;
while (!clear)
{
id = SOCK_get_char(sock);
mylog("got clear id = '%c'\n", id);
switch (id)
{
case 'I':
(void) SOCK_get_char(sock);
clear = TRUE;
break;
case 'Z':
break;
case 'C':
SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
qlog("Command response: '%s'\n", cmdbuffer);
break;
case 'N':
msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
if (QR_command_successful(res))
QR_set_status(res, PGRES_NONFATAL_ERROR);
QR_set_notice(res, cmdbuffer); /* will dup this string */
qlog("NOTICE from backend during clear: '%s'\n", cmdbuffer);
while (msg_truncated)
msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
break;
case 'E':
msg_truncated = SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
mylog("ERROR from backend during clear: '%s'\n", msgbuffer);
qlog("ERROR from backend during clear: '%s'\n", msgbuffer);
/*
* We must report this type of error as
* well (practically for reference
* integrity violation error reporting,
* from PostgreSQL 7.0). (Zoltan Kovacs,
* 04/26/2000)
*/
self->errormsg = msgbuffer;
if (!strncmp(self->errormsg, "FATAL", 5))
{
self->errornumber = CONNECTION_SERVER_REPORTED_ERROR;
CC_set_no_trans(self);
}
else
self->errornumber = CONNECTION_SERVER_REPORTED_WARNING;
QR_set_status(res, PGRES_FATAL_ERROR);
QR_set_aborted(res, TRUE);
while (msg_truncated)
msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
break;
}
}
mylog("send_query: returning res = %u\n", res);
break;
}
break;
case 'Z': /* Backend is ready for new query (6.4) */
if (empty_reqs == 0)
{
......
......@@ -274,6 +274,10 @@ struct ConnectionClass_
float pg_version_number;
Int2 pg_version_major;
Int2 pg_version_minor;
#ifdef MULTIBYTE
char *client_encoding;
char *server_encoding;
#endif /* MULTIBYTE */
};
......
......@@ -2666,6 +2666,180 @@ PGAPI_PrimaryKeys(
}
#ifdef MULTIBYTE
/*
* Multibyte support stuff for SQLForeignKeys().
* There may be much more effective way in the
* future version. The way is very forcive currently.
*/
static BOOL isMultibyte(const unsigned char *str)
{
for (; *str; str++)
{
if (*str >= 0x80)
return TRUE;
}
return FALSE;
}
static char *getClientTableName(ConnectionClass *conn, char *serverTableName, BOOL *nameAlloced)
{
char query[1024], saveoid[24], *ret = serverTableName;
BOOL continueExec = TRUE, bError = FALSE;
QResultClass *res;
*nameAlloced = FALSE;
if (!conn->client_encoding || !isMultibyte(serverTableName))
return ret;
if (!conn->server_encoding)
{
if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL), res)
{
if (QR_get_num_tuples(res) > 0)
conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
QR_Destructor(res);
}
}
if (!conn->server_encoding)
return ret;
sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
if (res = CC_send_query(conn, query, NULL), res)
{
bError = QR_get_aborted(res);
QR_Destructor(res);
}
else
bError = TRUE;
if (!bError && continueExec)
{
sprintf(query, "select OID from pg_class where relname = '%s'", serverTableName);
if (res = CC_send_query(conn, query, NULL), res)
{
if (QR_get_num_tuples(res) > 0)
strcpy(saveoid, QR_get_value_backend_row(res, 0, 0));
else
{
continueExec = FALSE;
bError = QR_get_aborted(res);
}
QR_Destructor(res);
}
else
bError = TRUE;
}
continueExec = (continueExec && !bError);
if (bError && CC_is_in_trans(conn))
{
if (res = CC_send_query(conn, "abort", NULL), res)
QR_Destructor(res);
CC_set_no_trans(conn);
bError = FALSE;
}
/* restore the client encoding */
sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
if (res = CC_send_query(conn, query, NULL), res)
{
bError = QR_get_aborted(res);
QR_Destructor(res);
}
else
bError = TRUE;
if (bError || !continueExec)
return ret;
sprintf(query, "select relname from pg_class where OID = %s", saveoid);
if (res = CC_send_query(conn, query, NULL), res)
{
if (QR_get_num_tuples(res) > 0)
{
ret = strdup(QR_get_value_backend_row(res, 0, 0));
*nameAlloced = TRUE;
}
QR_Destructor(res);
}
return ret;
}
static char *getClientColumnName(ConnectionClass *conn, const char *serverTableName, char *serverColumnName, BOOL *nameAlloced)
{
char query[1024], saveattrelid[24], saveattnum[16], *ret = serverColumnName;
BOOL continueExec = TRUE, bError = FALSE;
QResultClass *res;
*nameAlloced = FALSE;
if (!conn->client_encoding || !isMultibyte(serverColumnName))
return ret;
if (!conn->server_encoding)
{
if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL), res)
{
if (QR_get_num_tuples(res) > 0)
conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
QR_Destructor(res);
}
}
if (!conn->server_encoding)
return ret;
sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
if (res = CC_send_query(conn, query, NULL), res)
{
bError = QR_get_aborted(res);
QR_Destructor(res);
}
else
bError = TRUE;
if (!bError && continueExec)
{
sprintf(query, "select attrelid, attnum from pg_class, pg_attribute "
"where relname = '%s' and attrelid = pg_class.oid "
"and attname = '%s'", serverTableName, serverColumnName);
if (res = CC_send_query(conn, query, NULL), res)
{
if (QR_get_num_tuples(res) > 0)
{
strcpy(saveattrelid, QR_get_value_backend_row(res, 0, 0));
strcpy(saveattnum, QR_get_value_backend_row(res, 0, 1));
}
else
{
continueExec = FALSE;
bError = QR_get_aborted(res);
}
QR_Destructor(res);
}
else
bError = TRUE;
}
continueExec = (continueExec && !bError);
if (bError && CC_is_in_trans(conn))
{
if (res = CC_send_query(conn, "abort", NULL), res)
QR_Destructor(res);
CC_set_no_trans(conn);
bError = FALSE;
}
/* restore the cleint encoding */
sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
if (res = CC_send_query(conn, query, NULL), res)
{
bError = QR_get_aborted(res);
QR_Destructor(res);
}
else
bError = TRUE;
if (bError || !continueExec)
return ret;
sprintf(query, "select attname from pg_attribute where attrelid = %s and attnum = %s", saveattrelid, saveattnum);
if (res = CC_send_query(conn, query, NULL), res)
{
if (QR_get_num_tuples(res) > 0)
{
ret = strdup(QR_get_value_backend_row(res, 0, 0));
*nameAlloced = TRUE;
}
QR_Destructor(res);
}
return ret;
}
#endif /* MULTIBYTE */
RETCODE SQL_API
PGAPI_ForeignKeys(
HSTMT hstmt,
......@@ -2698,10 +2872,14 @@ PGAPI_ForeignKeys(
del_rule[MAX_TABLE_LEN];
char pk_table_needed[MAX_TABLE_LEN + 1];
char fk_table_needed[MAX_TABLE_LEN + 1];
char *pkey_ptr,
*fkey_ptr,
*pk_table,
*fk_table;
char *pkey_ptr, *pkey_text,
*fkey_ptr, *fkey_text,
*pk_table, *pkt_text,
*fk_table, *fkt_text;
#ifdef MULTIBYTE
BOOL pkey_alloced, fkey_alloced, pkt_alloced, fkt_alloced;
ConnectionClass *conn;
#endif /* MULTIBYTE */
int i,
j,
k,
......@@ -2795,6 +2973,10 @@ PGAPI_ForeignKeys(
make_string(szPkTableName, cbPkTableName, pk_table_needed);
make_string(szFkTableName, cbFkTableName, fk_table_needed);
#ifdef MULTIBYTE
pkey_alloced = fkey_alloced = pkt_alloced = fkt_alloced = FALSE;
conn = SC_get_conn(stmt);
#endif /* MULTIBYTE */
/*
* Case #2 -- Get the foreign keys in the specified table (fktab) that
* refer to the primary keys of other table(s).
......@@ -2954,18 +3136,24 @@ PGAPI_ForeignKeys(
for (k = 0; k < 2; k++)
pk_table += strlen(pk_table) + 1;
#ifdef MULTIBYTE
fk_table = trig_args + strlen(trig_args) + 1;
pkt_text = getClientTableName(conn, pk_table, &pkt_alloced);
#else
pkt_text = pk_table;
#endif /* MULTIBYTE */
/* If there is a pk table specified, then check it. */
if (pk_table_needed[0] != '\0')
{
/* If it doesn't match, then continue */
if (strcmp(pk_table, pk_table_needed))
if (strcmp(pkt_text, pk_table_needed))
{
result = PGAPI_Fetch(htbl_stmt);
continue;
}
}
keyresult = PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0, NULL, 0, pk_table, SQL_NTS);
keyresult = PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0, NULL, 0, pkt_text, SQL_NTS);
if (keyresult != SQL_SUCCESS)
{
stmt->errornumber = STMT_NO_MEMORY_ERROR;
......@@ -2975,8 +3163,6 @@ PGAPI_ForeignKeys(
return SQL_ERROR;
}
/* Check that the key listed is the primary key */
keyresult = PGAPI_Fetch(hpkey_stmt);
/* Get to first primary key */
pkey_ptr = trig_args;
......@@ -2985,17 +3171,32 @@ PGAPI_ForeignKeys(
for (k = 0; k < num_keys; k++)
{
mylog("%s: pkey_ptr='%s', pkey='%s'\n", func, pkey_ptr, pkey);
if (keyresult != SQL_SUCCESS || strcmp(pkey_ptr, pkey))
/* Check that the key listed is the primary key */
keyresult = PGAPI_Fetch(hpkey_stmt);
if (keyresult != SQL_SUCCESS)
{
num_keys = 0;
break;
}
#ifdef MULTIBYTE
pkey_text = getClientColumnName(conn, pk_table, pkey_ptr, &pkey_alloced);
#else
pkey_text = pkey_ptr;
#endif /* MULTIBYTE */
mylog("%s: pkey_ptr='%s', pkey='%s'\n", func, pkey_text, pkey);
if (strcmp(pkey_text, pkey))
{
num_keys = 0;
break;
}
#ifdef MULTIBYTE
if (pkey_alloced)
free(pkey_text);
#endif /* MULTIBYTE */
/* Get to next primary key */
for (k = 0; k < 2; k++)
pkey_ptr += strlen(pkey_ptr) + 1;
keyresult = PGAPI_Fetch(hpkey_stmt);
}
/* Set to first fk column */
......@@ -3045,17 +3246,24 @@ PGAPI_ForeignKeys(
{
row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func, pk_table, pkey_ptr);
#ifdef MULTIBYTE
pkey_text = getClientColumnName(conn, pk_table, pkey_ptr, &pkey_alloced);
fkey_text = getClientColumnName(conn, fk_table, fkey_ptr, &fkey_alloced);
#else
pkey_text = pkey_ptr;
fkey_text = fkey_ptr;
#endif /* MULTIBYTE */
mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func, pkt_text, pkey_text);
set_tuplefield_null(&row->tuple[0]);
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], pk_table);
set_tuplefield_string(&row->tuple[3], pkey_ptr);
set_tuplefield_string(&row->tuple[2], pkt_text);
set_tuplefield_string(&row->tuple[3], pkey_text);
mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n", func, fk_table_needed, fkey_ptr);
mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n", func, fk_table_needed, fkey_text);
set_tuplefield_null(&row->tuple[4]);
set_tuplefield_string(&row->tuple[5], "");
set_tuplefield_string(&row->tuple[6], fk_table_needed);
set_tuplefield_string(&row->tuple[7], fkey_ptr);
set_tuplefield_string(&row->tuple[7], fkey_text);
mylog("%s: upd_rule_type = '%i', del_rule_type = '%i'\n, trig_name = '%s'", func, upd_rule_type, del_rule_type, trig_args);
set_tuplefield_int2(&row->tuple[8], (Int2) (k + 1));
......@@ -3069,7 +3277,14 @@ PGAPI_ForeignKeys(
#endif /* ODBCVER >= 0x0300 */
QR_add_tuple(stmt->result, row);
#ifdef MULTIBYTE
if (fkey_alloced)
free(fkey_text);
fkey_alloced = FALSE;
if (pkey_alloced)
free(pkey_text);
pkey_alloced = FALSE;
#endif /* MULTIBYTE */
/* next primary/foreign key */
for (i = 0; i < 2; i++)
{
......@@ -3077,6 +3292,11 @@ PGAPI_ForeignKeys(
pkey_ptr += strlen(pkey_ptr) + 1;
}
}
#ifdef MULTIBYTE
if (pkt_alloced)
free(pkt_text);
pkt_alloced = FALSE;
#endif /* MULTIBYTE */
result = PGAPI_Fetch(htbl_stmt);
}
......@@ -3257,6 +3477,12 @@ PGAPI_ForeignKeys(
/* Get to first foreign table */
fk_table = trig_args;
fk_table += strlen(fk_table) + 1;
#ifdef MULTIBYTE
pk_table = fk_table + strlen(fk_table) + 1;
fkt_text = getClientTableName(conn, fk_table, &fkt_alloced);
#else
fkt_text = fk_table;
#endif /* MULTIBYTE */
/* Get to first foreign key */
fkey_ptr = trig_args;
......@@ -3265,21 +3491,28 @@ PGAPI_ForeignKeys(
for (k = 0; k < num_keys; k++)
{
mylog("pkey_ptr = '%s', fk_table = '%s', fkey_ptr = '%s'\n", pkey_ptr, fk_table, fkey_ptr);
#ifdef MULTIBYTE
pkey_text = getClientColumnName(conn, pk_table, pkey_ptr, &pkey_alloced);
fkey_text = getClientColumnName(conn, fk_table, fkey_ptr, &fkey_alloced);
#else
pkey_text = pkey_ptr;
fkey_text = fkey_ptr;
#endif /* MULTIBYTE */
mylog("pkey_ptr = '%s', fk_table = '%s', fkey_ptr = '%s'\n", pkey_text, fkt_text, fkey_text);
row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n", pk_table_needed, pkey_ptr);
mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n", pk_table_needed, pkey_text);
set_tuplefield_null(&row->tuple[0]);
set_tuplefield_string(&row->tuple[1], "");
set_tuplefield_string(&row->tuple[2], pk_table_needed);
set_tuplefield_string(&row->tuple[3], pkey_ptr);
set_tuplefield_string(&row->tuple[3], pkey_text);
mylog("fk_table = '%s', fkey_ptr = '%s'\n", fk_table, fkey_ptr);
mylog("fk_table = '%s', fkey_ptr = '%s'\n", fkt_text, fkey_text);
set_tuplefield_null(&row->tuple[4]);
set_tuplefield_string(&row->tuple[5], "");
set_tuplefield_string(&row->tuple[6], fk_table);
set_tuplefield_string(&row->tuple[7], fkey_ptr);
set_tuplefield_string(&row->tuple[6], fkt_text);
set_tuplefield_string(&row->tuple[7], fkey_text);
set_tuplefield_int2(&row->tuple[8], (Int2) (k + 1));
......@@ -3298,6 +3531,14 @@ PGAPI_ForeignKeys(
#endif /* ODBCVER >= 0x0300 */
QR_add_tuple(stmt->result, row);
#ifdef MULTIBYTE
if (pkey_alloced)
free(pkey_text);
pkey_alloced = FALSE;
if (fkey_alloced)
free(fkey_text);
fkey_alloced = FALSE;
#endif /* MULTIBYTE */
/* next primary/foreign key */
for (j = 0; j < 2; j++)
......@@ -3306,6 +3547,11 @@ PGAPI_ForeignKeys(
fkey_ptr += strlen(fkey_ptr) + 1;
}
}
#ifdef MULTIBYTE
if (fkt_alloced)
free(fkt_text);
fkt_alloced = FALSE;
#endif /* MULTIBYTE */
result = PGAPI_Fetch(htbl_stmt);
}
}
......@@ -3317,6 +3563,16 @@ PGAPI_ForeignKeys(
PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
return SQL_ERROR;
}
#ifdef MULTIBYTE
if (pkt_alloced)
free(pkt_text);
if (pkey_alloced)
free(pkey_text);
if (fkt_alloced)
free(fkt_text);
if (fkey_alloced)
free(fkey_text);
#endif /* MULTIBYTE */
PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
......
......@@ -227,12 +227,17 @@ QR_set_field_info(stmt->result, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
void
getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
{
char *str;
if (fi->name[0] == '\0')
strcpy(fi->name, QR_get_value_manual(col_info->result, k, 3));
fi->type = atoi(QR_get_value_manual(col_info->result, k, 13));
fi->precision = atoi(QR_get_value_manual(col_info->result, k, 6));
fi->length = atoi(QR_get_value_manual(col_info->result, k, 7));
if (str = QR_get_value_manual(col_info->result, k, 8), str)
fi->scale = atoi(str);
else
fi->scale = -1;
fi->nullable = atoi(QR_get_value_manual(col_info->result, k, 10));
fi->display_size = atoi(QR_get_value_manual(col_info->result, k, 12));
}
......
......@@ -199,7 +199,7 @@ PGAPI_DescribeCol(
QResultClass *res;
char *col_name = NULL;
Int4 fieldtype = 0;
int precision = 0;
int precision = 0, scale = 0;
ConnInfo *ci;
char parse_ok;
char buf[255];
......@@ -250,6 +250,7 @@ PGAPI_DescribeCol(
fieldtype = stmt->fi[icol]->type;
col_name = stmt->fi[icol]->name;
precision = stmt->fi[icol]->precision;
scale = stmt->fi[icol]->scale;
mylog("PARSE: fieldtype=%d, col_name='%s', precision=%d\n", fieldtype, col_name, precision);
if (fieldtype > 0)
......@@ -292,6 +293,7 @@ PGAPI_DescribeCol(
/* atoi(ci->unknown_sizes) */
precision = pgtype_precision(stmt, fieldtype, icol, ci->drivers.unknown_sizes);
scale = pgtype_scale(stmt, fieldtype, icol);
}
mylog("describeCol: col %d fieldname = '%s'\n", icol, col_name);
......@@ -348,10 +350,7 @@ PGAPI_DescribeCol(
*/
if (pibScale)
{
Int2 scale;
scale = pgtype_scale(stmt, fieldtype, icol);
if (scale == -1)
if (scale < 0)
scale = 0;
*pibScale = scale;
......
......@@ -131,6 +131,7 @@ typedef struct
{
TABLE_INFO *ti; /* resolve to explicit table names */
int precision;
int scale;
int display_size;
int length;
int type;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册