📄 dblib.c
字号:
tdsdump_log(TDS_DBG_FUNC, "dbnextrow() dbresults_state = %d (%s)\n", dbproc->dbresults_state, prdbresults_state(dbproc->dbresults_state)); if (!resinfo || dbproc->dbresults_state != _DB_RES_RESULTSET_ROWS) { /* no result set or result set empty (no rows) */ tdsdump_log(TDS_DBG_FUNC, "leaving dbnextrow() returning %d (NO_MORE_ROWS)\n", NO_MORE_ROWS); return dbproc->row_type = NO_MORE_ROWS; } /* * Try to get the dbproc->row_buf.current item from the buffered rows, if any. * Else read from the stream, unless the buffer is exhausted. * If no rows are read, DBROWTYPE() will report NO_MORE_ROWS. */ dbproc->row_type = NO_MORE_ROWS; computeid = REG_ROW; if (-1 != (idx = buffer_current_index(dbproc))) { /* * Cool, the item we want is already there */ result = dbproc->row_type = REG_ROW; res_type = TDS_ROW_RESULT; } else if (buffer_is_full(&dbproc->row_buf)) { result = BUF_FULL; res_type = TDS_ROWFMT_RESULT; } else { const int mask = TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE; buffer_save_row(dbproc); /* Get the row from the TDS stream. */ switch (tds_process_tokens(tds, &res_type, NULL, mask)) { case TDS_SUCCEED: if (res_type == TDS_ROW_RESULT || res_type == TDS_COMPUTE_RESULT) { if (res_type == TDS_COMPUTE_RESULT) computeid = tds->current_results->computeid; /* Add the row to the row buffer, whose capacity is always at least 1 */ resinfo = tds->current_results; idx = buffer_add_row(dbproc, resinfo); assert(idx != -1); result = dbproc->row_type = (res_type == TDS_ROW_RESULT)? REG_ROW : computeid;#if 0 /* TODO */ tds_process_tokens(tds, &res_type, NULL, TDS_TOKEN_TRAILING);#endif break; } case TDS_NO_MORE_RESULTS: dbproc->dbresults_state = _DB_RES_NEXT_RESULT; result = NO_MORE_ROWS; break; default: tdsdump_log(TDS_DBG_FUNC, "unexpected: leaving dbnextrow() returning FAIL\n"); return FAIL; break; } } if (res_type == TDS_ROW_RESULT || res_type == TDS_COMPUTE_RESULT) { /* * Transfer the data from the row buffer to the bound variables. */ buffer_transfer_bound_data(&dbproc->row_buf, res_type, computeid, dbproc, idx); } if (res_type == TDS_COMPUTE_RESULT) { tdsdump_log(TDS_DBG_FUNC, "leaving dbnextrow() returning compute_id %d\n", result); } else { tdsdump_log(TDS_DBG_FUNC, "leaving dbnextrow() returning %s\n", prdbretcode(result)); } return result;} /* dbnextrow() */static int_db_get_server_type(int bindtype){ switch (bindtype) { case CHARBIND: case STRINGBIND: case NTBSTRINGBIND: return SYBCHAR; break; case FLT8BIND: return SYBFLT8; break; case REALBIND: return SYBREAL; break; case INTBIND: return SYBINT4; break; case SMALLBIND: return SYBINT2; break; case TINYBIND: return SYBINT1; break; case DATETIMEBIND: return SYBDATETIME; break; case SMALLDATETIMEBIND: return SYBDATETIME4; break; case MONEYBIND: return SYBMONEY; break; case SMALLMONEYBIND: return SYBMONEY4; break; case BINARYBIND: return SYBBINARY; break; case VARYCHARBIND: return SYBVARCHAR; break; case BITBIND: return SYBBIT; break; case NUMERICBIND: return SYBNUMERIC; break; case DECIMALBIND: return SYBDECIMAL; break; default: return -1; break; }}/** * \ingroup dblib_core * \brief Convert one datatype to another. * * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param srctype datatype of the data to convert. * \param src buffer to convert * \param srclen length of \a src * \param desttype target datatype * \param dest output buffer * \param destlen size of \a dest * \returns On success, the count of output bytes in \a dest, else -1. On failure, it will call any user-supplied error handler. * \remarks Causes of failure: * - No such conversion unavailable. * - Character data output was truncated, or numerical data overflowed or lost precision. * - In converting character data to one of the numeric types, the string could not be interpreted as a number. * * Conversion functions are handled in the TDS layer. * * The main reason for this is that \c ct-lib and \c ODBC (and presumably \c DBI) need * to be able to do conversions between datatypes. This is possible because * the format of complex data (dates, money, numeric, decimal) is defined by * its representation on the wire; thus what we call \c DBMONEY is exactly its * format on the wire. CLIs that need a different representation (ODBC?) * need to convert from this format anyway, so the code would already be in * place. * * Each datatype is also defined by its Server-type so all CLIs should be * able to map native types to server types as well. * * tds_convert() copies from src to dest and returns the output data length, * period. All padding and termination is the responsibility of the API library * and is done post-conversion. The peculiar rule in dbconvert() is that * a \a destlen of -1 and a \a desttype of \c SYBCHAR means the output buffer * should be null-terminated. * * \sa dbaltbind(), dbaltbind_ps(), dbbind(), dbbind_ps(), dbconvert_ps(), dberrhandle(), dbsetnull(), dbsetversion(), dbwillconvert(). * \todo What happens if client does not reset values? * \todo Microsoft and Sybase define this function differently. */DBINTdbconvert(DBPROCESS * dbproc, int srctype, const BYTE * src, DBINT srclen, int desttype, BYTE * dest, DBINT destlen){ CONV_RESULT dres; DBINT ret; int i; int len; DBNUMERIC *num; tdsdump_log(TDS_DBG_FUNC, "dbconvert(%p, %s, %p, %d, %s, %p, %d)\n", dbproc, tds_prdatatype(srctype), src, srclen, tds_prdatatype(desttype), dest, destlen); /* dbproc and src can be NULLs */ CHECK_PARAMETER(dest, SYBEACNV, -1); if (0 == destlen) return 0; if (src == NULL || srclen == 0) { int bind = dbbindtype(desttype); int size = tds_get_size_by_type(desttype); if (SYBCHAR == desttype) { if (destlen > 0) { size = destlen; bind = CHARBIND; } else { size = 1; bind = NTBSTRINGBIND; } } dbgetnull(dbproc, bind, size, dest); return size; } /* srclen of -1 means the source data is definitely NULL terminated */ if (srclen == -1) srclen = strlen((const char *) src); /* oft times we are asked to convert a data type to itself */ if (srctype == desttype) { ret = -2; /* to make sure we always set it */ tdsdump_log(TDS_DBG_INFO1, "dbconvert() srctype == desttype\n"); switch (desttype) { case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: if (srclen > destlen && destlen >= 0) { dbperror(dbproc, SYBECOFL, 0); ret = -1; } else { memcpy(dest, src, srclen); if (srclen < destlen) memset(dest + srclen, 0, destlen - srclen); ret = srclen; } break; case SYBCHAR: case SYBVARCHAR: case SYBTEXT: /* srclen of -1 means the source data is definitely NULL terminated */ if (srclen == -1) srclen = strlen((const char *) src); switch (destlen) { case 0: /* nothing to copy */ ret = 0; break; case -1: /* rtrim and null terminate */ while (srclen && src[srclen - 1] == ' ') { --srclen; } /* fall thru */ case -2: /* just null terminate */ memcpy(dest, src, srclen); dest[srclen] = '\0'; ret = srclen; break; default: assert(destlen > 0); if (destlen < 0 || srclen > destlen) { dbperror(dbproc, SYBECOFL, 0); ret = -1; } else { memcpy(dest, src, srclen); for (i = srclen; i < destlen; i++) dest[i] = ' '; ret = srclen; } break; } break; case SYBINT1: case SYBINT2: case SYBINT4: case SYBINT8: case SYBFLT8: case SYBREAL: case SYBBIT: case SYBBITN: case SYBMONEY: case SYBMONEY4: case SYBDATETIME: case SYBDATETIME4: case SYBUNIQUE: ret = tds_get_size_by_type(desttype); memcpy(dest, src, ret); break; case SYBNUMERIC: case SYBDECIMAL: memcpy(dest, src, sizeof(DBNUMERIC)); ret = sizeof(DBNUMERIC); break; default: ret = -1; break; } assert(ret > -2); return ret; } /* end srctype == desttype */ assert(srctype != desttype); /* * Character types need no conversion. Just move the data. */ if (is_similar_type(srctype, desttype)) { if (src && dest && srclen > 0 && destlen >= srclen) { memcpy(dest, src, srclen); return srclen; } } /* FIXME what happen if client do not reset values ??? */ /* FIXME act differently for ms and sybase */ if (is_numeric_type(desttype)) { num = (DBNUMERIC *) dest; if (num->precision == 0) dres.n.precision = 18; else dres.n.precision = num->precision; if (num->scale == 0) dres.n.scale = 0; else dres.n.scale = num->scale; } tdsdump_log(TDS_DBG_INFO1, "dbconvert() calling tds_convert\n"); len = tds_convert(g_dblib_ctx.tds_ctx, srctype, (const TDS_CHAR *) src, srclen, desttype, &dres); tdsdump_log(TDS_DBG_INFO1, "dbconvert() called tds_convert returned %d\n", len); switch (len) { case TDS_CONVERT_NOAVAIL: dbperror(dbproc, SYBERDCN, 0); return -1; break; case TDS_CONVERT_SYNTAX: dbperror(dbproc, SYBECSYN, 0); return -1; break; case TDS_CONVERT_NOMEM: dbperror(dbproc, SYBEMEM, ENOMEM); return -1; break; case TDS_CONVERT_OVERFLOW: dbperror(dbproc, SYBECOFL, 0); return -1; break; case TDS_CONVERT_FAIL: dbperror(dbproc, SYBECINTERNAL, 0); return -1; break; default: if (len < 0) { /* logic error: should be captured above */ dbperror(dbproc, SYBECINTERNAL, 0); return -1; } break; } switch (desttype) { case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: if (len > destlen && destlen >= 0) { dbperror(dbproc, SYBECOFL, 0); ret = -1; } else { memcpy(dest, dres.ib, len); free(dres.ib); if (len < destlen) memset(dest + len, 0, destlen - len); ret = len; } break; case SYBINT1: memcpy(dest, &(dres.ti), 1); ret = 1; break; case SYBINT2: memcpy(dest, &(dres.si), 2); ret = 2; break; case SYBINT4: memcpy(dest, &(dres.i), 4); ret = 4; break; case SYBINT8: memcpy(dest, &(dres.bi), 8); ret = 8; break; case SYBFLT8: memcpy(dest, &(dres.f), 8); ret = 8; break; case SYBREAL: memcpy(dest, &(dres.r), 4); ret = 4; break; case SYBBIT: case SYBBITN: memcpy(dest, &(dres.ti), 1); ret = 1; break; case SYBMONEY: memcpy(dest, &(dres.m), sizeof(TDS_MONEY)); ret = sizeof(TDS_MONEY); break; case SYBMONEY4: memcpy(dest, &(dres.m4), sizeof(TDS_MONEY4)); ret = sizeof(TDS_MONEY4); break; case SYBDATETIME: memcpy(dest, &(dres.dt), sizeof(TDS_DATETIME)); ret = sizeof(TDS_DATETIME); break; case SYBDATETIME4: memcpy(dest, &(dres.dt4), sizeof(TDS_DATETIME4)); ret = sizeof(TDS_DATETIME4); break; case SYBNUMERIC: case SYBDECIMAL: memcpy(dest, &(dres.n), sizeof(TDS_NUMERIC)); ret = sizeof(TDS_NUMERIC); break; case SYBUNIQUE: memcpy(dest, &(dres.u), sizeof(TDS_UNIQUE)); ret = sizeof(TDS_UNIQUE); break; case SYBCHAR: case SYBVARCHAR: case SYBTEXT: tdsdump_log(TDS_DBG_INFO1, "dbconvert() outputting %d bytes character data destlen = %d \n", len, destlen); if (destlen < -2) destlen = 0; /* failure condition */ switch (destlen) { case 0: ret = FAIL; break; case -1: /* rtrim and null terminate */ for (i = len - 1; i >= 0 && dres.c[i] == ' '; --i) { len = i; } memcpy(dest, dres.c, len); dest[len] = '\0'; ret = len; break; case -2: /* just null terminate */ memcpy(dest, dres.c, len); dest[len] = 0; ret = len; break; default: assert(destlen > 0); if (destlen < 0 || len > destlen) { dbperror(dbproc, SYBECOFL, 0); ret = -1; tdsdump_log(TDS_DBG_INFO1, "%d bytes type %d -> %d, destlen %d < %d required\n", srclen, srctype, desttype, destlen, len); break; } /* else pad with blanks */ memcpy(dest, dres.c, len); for (i = len; i < destlen; i++) dest[i] = ' '; ret = len; break; } free(dres.c); break; default: tdsdump_log(TDS_DBG_INFO1, "error: dbconvert(): unrecognized desttype %d \n", desttype); ret = -1; break; } return (ret);}/** * \ingroup dblib_core * \brief cf. dbconvert(), above * * \em Sybase: Convert numeric types. * \param dbproc contains all information needed by db-lib to manage com
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -