int main(int argc, char **argv) { TDSRESULTINFO *info; char mymsg[256]; fprintf(stdout, "%s: Testing flags from server\n", __FILE__); if (try_tds_login(&login, &tds, __FILE__, 0) != TDS_SUCCESS) { fprintf(stderr, "try_tds_login() failed\n"); return 1; } if (run_query(tds, "create table #tmp1 (i numeric(10,0) identity primary key, b varchar(20) null, c int not null)") != TDS_SUCCESS) fatal_error("creating table error"); /* TDS 4.2 without FOR BROWSE clause seem to forget flags... */ if (!IS_TDS42(tds->conn)) { /* check select of all fields */ test_begin("select * from #tmp1"); info = tds->current_results; if (info->num_cols != 3) { sprintf(mymsg,"wrong number of columns returned expected 3 got %d", info->num_cols); fatal_error(mymsg); } check_flags(info->columns[0], 0, "identity"); check_flags(info->columns[1], 1, "nullable writable"); check_flags(info->columns[2], 2, "writable"); test_end(); } /* check select of 2 field */ test_begin("select c, b from #tmp1 for browse"); info = tds->current_results; if (info->num_cols != 3) fatal_error("wrong number of columns returned"); check_flags(info->columns[0], 0, "writable"); if (!IS_TDS42(tds->conn)) { check_flags(info->columns[1], 1, "nullable writable"); } else { check_flags(info->columns[1], 1, "writable-nullable writable"); } /* TDS5 return not identity information altough documented.. */ check_flags(info->columns[2], 2, "writable identity key hidden-writable key hidden"); test_end(); try_tds_logout(login, tds, 0); return 0; }
/** * Go looking for trouble. Return NULL if the info is okay, or an error message * if something needs to change. */ static const char * validate(DSNINFO * di) { if (!SQLValidDSN(tds_dstr_cstr(&di->dsn))) return "Invalid DSN"; if (!IS_TDS42(di->login) && !IS_TDS46(di->login) && !IS_TDS50(di->login) && !IS_TDS7_PLUS(di->login)) return "Bad Protocol version"; if (tds_dstr_isempty(&di->login->server_name)) return "Address is required"; if (di->login->port < 1 || di->login->port > 65535) return "Bad port - Try 1433 or 4000"; return NULL; }
/** * Read in one 'packet' from the server. This is a wrapped outer packet of * the protocol (they bundle result packets into chunks and wrap them at * what appears to be 512 bytes regardless of how that breaks internal packet * up. (tetherow\@nol.org) * @return bytes read or -1 on failure */ int tds_read_packet(TDSSOCKET * tds) { unsigned char header[8]; int len; int x = 0, have, need; if (IS_TDSDEAD(tds)) { tdsdump_log(TDS_DBG_NETWORK, "Read attempt when state is TDS_DEAD"); return -1; } /* * Read in the packet header. We use this to figure out our packet * length */ /* * Cast to int are needed because some compiler seem to convert * len to unsigned (as FreeBSD 4.5 one) */ if ((len = goodread(tds, header, sizeof(header))) < (int) sizeof(header)) { /* GW ADDED */ if (len < 0) { tds_client_msg(tds->tds_ctx, tds, 20004, 6, 0, 0, "Read from SQL server failed."); tds_close_socket(tds); tds->in_len = 0; tds->in_pos = 0; return -1; } /* GW ADDED */ /* * Not sure if this is the best way to do the error * handling here but this is the way it is currently * being done. */ tds->in_len = 0; tds->in_pos = 0; tds->last_packet = 1; if (tds->state != TDS_IDLE && len == 0) { tds_close_socket(tds); } return -1; } tdsdump_dump_buf(TDS_DBG_NETWORK, "Received header", header, sizeof(header)); #if 0 /* * Note: * this was done by Gregg, I don't think its the real solution (it breaks * under 5.0, but I haven't gotten a result big enough to test this yet. */ if (IS_TDS42(tds)) { if (header[0] != 0x04 && header[0] != 0x0f) { tdsdump_log(TDS_DBG_ERROR, "Invalid packet header %d\n", header[0]); /* * Not sure if this is the best way to do the error * handling here but this is the way it is currently * being done. */ tds->in_len = 0; tds->in_pos = 0; tds->last_packet = 1; return (-1); } } #endif /* Convert our packet length from network to host byte order */ len = ((((unsigned int) header[2]) << 8) | header[3]) - 8; need = len; /* * If this packet size is the largest we have gotten allocate * space for it */ if ((unsigned int)len > tds->in_buf_max) { unsigned char *p; if (!tds->in_buf) { p = (unsigned char *) malloc(len); } else { p = (unsigned char *) realloc(tds->in_buf, len); } if (!p) return -1; /* FIXME should close socket too */ tds->in_buf = p; /* Set the new maximum packet size */ tds->in_buf_max = len; } /* Clean out the in_buf so we don't use old stuff by mistake */ memset(tds->in_buf, 0, tds->in_buf_max); /* Now get exactly how many bytes the server told us to get */ have = 0; while (need > 0) { if ((x = goodread(tds, tds->in_buf + have, need)) < 1) { /* * Not sure if this is the best way to do the error * handling here but this is the way it is currently * being done. */ tds->in_len = 0; tds->in_pos = 0; tds->last_packet = 1; /* FIXME should this be "if (x == 0)" ? */ if (len == 0) { tds_close_socket(tds); } return (-1); } have += x; need -= x; } if (x < 1) { /* * Not sure if this is the best way to do the error handling * here but this is the way it is currently being done. */ tds->in_len = 0; tds->in_pos = 0; tds->last_packet = 1; /* return 0 if header found but no payload */ return len ? -1 : 0; } /* Set the last packet flag */ if (header[1]) { tds->last_packet = 1; } else { tds->last_packet = 0; } /* set the received packet type flag */ tds->in_flag = header[0]; /* Set the length and pos (not sure what pos is used for now */ tds->in_len = have; tds->in_pos = 0; tdsdump_dump_buf(TDS_DBG_NETWORK, "Received packet", tds->in_buf, tds->in_len); return (tds->in_len); }