📄 connection.c
字号:
StartupPacket6_2 sp62;QResultClass *res;SocketClass *sock;ConnInfo *ci = &(self->connInfo);int areq = -1;int beresp;char msgbuffer[ERROR_MSG_LENGTH]; char salt[2];static char *func="CC_connect"; mylog("%s: entering...\n", func); if ( do_password) sock = self->sock; /* already connected, just authenticate */ else { qlog("Global Options: Version='%s', fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n", POSTGRESDRIVERVERSION, globals.fetch_max, globals.socket_buffersize, globals.unknown_sizes, globals.max_varchar_size, globals.max_longvarchar_size); qlog(" disable_optimizer=%d, ksqo=%d, unique_index=%d, use_declarefetch=%d\n", globals.disable_optimizer, globals.ksqo, globals.unique_index, globals.use_declarefetch); qlog(" text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d\n", globals.text_as_longvarchar, globals.unknowns_as_longvarchar, globals.bools_as_char); qlog(" extra_systable_prefixes='%s', conn_settings='%s'\n", globals.extra_systable_prefixes, globals.conn_settings); if (self->status != CONN_NOT_CONNECTED) { self->errormsg = "Already connected."; self->errornumber = CONN_OPENDB_ERROR; return 0; } if ( ci->server[0] == '\0' || ci->port[0] == '\0' || ci->database[0] == '\0') { self->errornumber = CONN_INIREAD_ERROR; self->errormsg = "Missing server name, port, or database name in call to CC_connect."; return 0; } mylog("CC_connect(): DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n", ci->dsn, ci->server, ci->port, ci->database, ci->username, ci->password); /* If the socket was closed for some reason (like a SQLDisconnect, but no SQLFreeConnect then create a socket now. */ if ( ! self->sock) { self->sock = SOCK_Constructor(); if ( ! self->sock) { self->errornumber = CONNECTION_SERVER_NOT_REACHED; self->errormsg = "Could not open a socket to the server"; return 0; } } sock = self->sock; mylog("connecting to the server socket...\n"); SOCK_connect_to(sock, (short) atoi(ci->port), ci->server); if (SOCK_get_errcode(sock) != 0) { mylog("connection to the server socket failed.\n"); self->errornumber = CONNECTION_SERVER_NOT_REACHED; self->errormsg = "Could not connect to the server"; return 0; } mylog("connection to the server socket succeeded.\n"); if ( PROTOCOL_62(ci)) { sock->reverse = TRUE; /* make put_int and get_int work for 6.2 */ memset(&sp62, 0, sizeof(StartupPacket6_2)); SOCK_put_int(sock, htonl(4+sizeof(StartupPacket6_2)), 4); sp62.authtype = htonl(NO_AUTHENTICATION); strncpy(sp62.database, ci->database, PATH_SIZE); strncpy(sp62.user, ci->username, NAMEDATALEN); SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2)); SOCK_flush_output(sock); } else { memset(&sp, 0, sizeof(StartupPacket)); mylog("sizeof startup packet = %d\n", sizeof(StartupPacket)); // Send length of Authentication Block SOCK_put_int(sock, 4+sizeof(StartupPacket), 4); if ( PROTOCOL_63(ci)) sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_63); else sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LATEST); strncpy(sp.database, ci->database, SM_DATABASE); strncpy(sp.user, ci->username, SM_USER); SOCK_put_n_char(sock, (char *) &sp, sizeof(StartupPacket)); SOCK_flush_output(sock); } mylog("sent the authentication block.\n"); if (sock->errornumber != 0) { mylog("couldn't send the authentication block properly.\n"); self->errornumber = CONN_INVALID_AUTHENTICATION; self->errormsg = "Sending the authentication packet failed"; return 0; } mylog("sent the authentication block successfully.\n"); } mylog("gonna do authentication\n"); // *************************************************** // Now get the authentication request from backend // *************************************************** if ( ! PROTOCOL_62(ci)) do { if (do_password) beresp = 'R'; else beresp = SOCK_get_char(sock); switch(beresp) { case 'E': mylog("auth got 'E'\n"); SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH); self->errornumber = CONN_INVALID_AUTHENTICATION; self->errormsg = msgbuffer; qlog("ERROR from backend during authentication: '%s'\n", self->errormsg); return 0; case 'R': if (do_password) { mylog("in 'R' do_password\n"); areq = AUTH_REQ_PASSWORD; do_password = FALSE; } else { mylog("auth got 'R'\n"); areq = SOCK_get_int(sock, 4); if (areq == AUTH_REQ_CRYPT) SOCK_get_n_char(sock, salt, 2); mylog("areq = %d\n", areq); } switch(areq) { case AUTH_REQ_OK: break; case AUTH_REQ_KRB4: self->errormsg = "Kerberos 4 authentication not supported"; self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED; return 0; case AUTH_REQ_KRB5: self->errormsg = "Kerberos 5 authentication not supported"; self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED; return 0; case AUTH_REQ_PASSWORD: mylog("in AUTH_REQ_PASSWORD\n"); if (ci->password[0] == '\0') { self->errornumber = CONNECTION_NEED_PASSWORD; self->errormsg = "A password is required for this connection."; return -1; /* need password */ } mylog("past need password\n"); SOCK_put_int(sock, 4+strlen(ci->password)+1, 4); SOCK_put_n_char(sock, ci->password, strlen(ci->password) + 1); SOCK_flush_output(sock); mylog("past flush\n"); break; case AUTH_REQ_CRYPT: self->errormsg = "Password crypt authentication not supported"; self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED; return 0; default: self->errormsg = "Unknown authentication type"; self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED; return 0; } break; default: self->errormsg = "Unexpected protocol character during authentication"; self->errornumber = CONN_INVALID_AUTHENTICATION; return 0; } } while (areq != AUTH_REQ_OK); CC_clear_error(self); /* clear any password error */ /* send an empty query in order to find out whether the specified */ /* database really exists on the server machine */ mylog("sending an empty query...\n"); res = CC_send_query(self, " ", NULL); if ( res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY) { mylog("got no result from the empty query. (probably database does not exist)\n"); self->errornumber = CONNECTION_NO_SUCH_DATABASE; self->errormsg = "The database does not exist on the server\nor user authentication failed."; if (res != NULL) QR_Destructor(res); return 0; } if (res) QR_Destructor(res); mylog("empty query seems to be OK.\n"); CC_set_translation (self); /**********************************************/ /******* Send any initial settings *********/ /**********************************************/ /* Since these functions allocate statements, and since the connection is not established yet, it would violate odbc state transition rules. Therefore, these functions call the corresponding local function instead. */ CC_send_settings(self); CC_lookup_lo(self); /* a hack to get the oid of our large object oid type */ CC_clear_error(self); /* clear any initial command errors */ self->status = CONN_CONNECTED; mylog("%s: returning...\n", func); return 1;}charCC_add_statement(ConnectionClass *self, StatementClass *stmt){int i; mylog("CC_add_statement: self=%u, stmt=%u\n", self, stmt); for (i = 0; i < self->num_stmts; i++) { if ( ! self->stmts[i]) { stmt->hdbc = self; self->stmts[i] = stmt; return TRUE; } } /* no more room -- allocate more memory */ self->stmts = (StatementClass **) realloc( self->stmts, sizeof(StatementClass *) * (STMT_INCREMENT + self->num_stmts)); if ( ! self->stmts) return FALSE; memset(&self->stmts[self->num_stmts], 0, sizeof(StatementClass *) * STMT_INCREMENT); stmt->hdbc = self; self->stmts[self->num_stmts] = stmt; self->num_stmts += STMT_INCREMENT; return TRUE;}char CC_remove_statement(ConnectionClass *self, StatementClass *stmt){int i; for (i = 0; i < self->num_stmts; i++) { if (self->stmts[i] == stmt && stmt->status != STMT_EXECUTING) { self->stmts[i] = NULL; return TRUE; } } return FALSE;}/* Create a more informative error message by concatenating the connection error message with its socket error message.*/char *CC_create_errormsg(ConnectionClass *self){SocketClass *sock = self->sock;int pos;static char msg[4096]; mylog("enter CC_create_errormsg\n"); msg[0] = '\0'; if (self->errormsg) strcpy(msg, self->errormsg); mylog("msg = '%s'\n", msg); if (sock && sock->errormsg && sock->errormsg[0] != '\0') { pos = strlen(msg); sprintf(&msg[pos], ";\n%s", sock->errormsg); } mylog("exit CC_create_errormsg\n"); return msg;}char CC_get_error(ConnectionClass *self, int *number, char **message){int rv; mylog("enter CC_get_error\n"); // Create a very informative errormsg if it hasn't been done yet. if ( ! self->errormsg_created) { self->errormsg = CC_create_errormsg(self); self->errormsg_created = TRUE; } if (self->errornumber) { *number = self->errornumber; *message = self->errormsg; } rv = (self->errornumber != 0); self->errornumber = 0; // clear the error mylog("exit CC_get_error\n"); return rv;}/* The "result_in" is only used by QR_next_tuple() to fetch another group of rows into the same existing QResultClass (this occurs when the tuple cache is depleted and needs to be re-filled). The "cursor" is used by SQLExecute to associate a statement handle as the cursor name (i.e., C3326857) for SQL select statements. This cursor is then used in future 'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.*/QResultClass *CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi){QResultClass *result_in, *res = NULL;char id, swallow;SocketClass *sock = self->sock;static char msgbuffer[MAX_MESSAGE_LEN+1];char cmdbuffer[MAX_MESSAGE_LEN+1]; // QR_set_command() dups this string so dont need static mylog("send_query(): conn=%u, query='%s'\n", self, query); qlog("conn=%u, query='%s'\n", self, query); // Indicate that we are sending a query to the backend if(strlen(query) > MAX_MESSAGE_LEN-2) { self->errornumber = CONNECTION_MSG_TOO_LONG; self->errormsg = "Query string is too long"; return NULL; } if ((NULL == query) || (query[0] == '\0')) return NULL; if (SOCK_get_errcode(sock) != 0) { self->errornumber = CONNECTION_COULD_NOT_SEND; self->errormsg = "Could not send Query to backend"; CC_set_no_trans(self); return NULL; } SOCK_put_char(sock, 'Q'); if (SOCK_get_errcode(sock) != 0) { self->errornumber = CONNECTION_COULD_NOT_SEND; self->errormsg = "Could not send Query to backend"; CC_set_no_trans(self); return NULL; } SOCK_put_string(sock, query); SOCK_flush_output(sock); if (SOCK_get_errcode(sock) != 0) { self->errornumber = CONNECTION_COULD_NOT_SEND; self->errormsg = "Could not send Query to backend"; CC_set_no_trans(self); return NULL; } mylog("send_query: done sending query\n"); while(1) { /* what type of message is coming now ? */ id = SOCK_get_char(sock); if ((SOCK_get_errcode(sock) != 0) || (id == EOF)) { self->errornumber = CONNECTION_NO_RESPONSE; self->errormsg = "No response from the backend"; if (res) QR_Destructor(res); mylog("send_query: 'id' - %s\n", self->errormsg); CC_set_no_trans(self); return NULL; } mylog("send_query: got id = '%c'\n", id); switch (id) { case 'A' : /* Asynchronous Messages are ignored */ (void)SOCK_get_int(sock, 4); /* id of notification */ SOCK_get_string(sock, msgbuffer, MAX_MESSAGE_LEN); /* name of the relation the message comes from */ break; case 'C' : /* portal query command, no tuples returned */ /* read in the return message from the backend */ SOCK_get_string(sock, cmdbuffer, MAX_MESSAGE_LEN); if (SOCK_get_errcode(sock) != 0) { self->errornumber = CONNECTION_NO_RESPONSE; self->errormsg = "No response from backend while receiving a portal query command"; mylog("send_query: 'C' - %s\n", self->errormsg); CC_set_no_trans(self); return NULL; } else { char clear = 0; mylog("send_query: ok - 'C' - %s\n", cmdbuffer); if (res == NULL) /* allow for "show" style notices */ res = QR_Constructor(); mylog("send_query: setting cmdbuffer = '%s'\n", cmdbuffer); /* Only save the first command */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -