/** * Reads a string from wire and put in a DSTR. * On error we read the bytes from the wire anyway. * \tds * \param[out] s output string * \param[in] len string length (in characters) * \return string or NULL on error */ DSTR* tds_dstr_get(TDSSOCKET * tds, DSTR * s, size_t len) { size_t out_len; CHECK_TDS_EXTRA(tds); /* assure sufficient space for every conversion */ if (TDS_UNLIKELY(!tds_dstr_alloc(s, len * 4))) { tds_get_n(tds, NULL, len); return NULL; } out_len = tds_get_string(tds, len, tds_dstr_buf(s), len * 4); tds_dstr_setlen(s, out_len); return s; }
/* * Function transformation (from ODBC to Sybase) * String functions * ASCII(string) -> ASCII(string) * BIT_LENGTH(string) -> 8*OCTET_LENGTH(string) * CHAR_LENGTH(string_exp) -> CHAR_LENGTH(string_exp) * CHARACTER_LENGTH(string_exp) -> CHAR_LENGTH(string_exp) * CONCAT(string_exp1, string_exp2) -> string_exp1 + string_exp2 * DIFFERENCE(string_exp1, string_exp2) -> DIFFERENCE(string_exp1, string_exp2) * INSERT(string_exp1, start, length, string_exp2) -> STUFF(sameparams) * LCASE(string_exp) -> LOWER(string) * LEFT(string_exp, count) -> SUBSTRING(string, 1, count) * LENGTH(string_exp) -> CHAR_LENGTH(RTRIM(string_exp)) * LOCATE(string, string [,start]) -> CHARINDEX(string, string) * (SQLGetInfo should return third parameter not possible) * LTRIM(String) -> LTRIM(String) * OCTET_LENGTH(string_exp) -> OCTET_LENGTH(string_exp) * POSITION(character_exp IN character_exp) ??? * REPEAT(string_exp, count) -> REPLICATE(same) * REPLACE(string_exp1, string_exp2, string_exp3) -> ?? * RIGHT(string_exp, count) -> RIGHT(string_exp, count) * RTRIM(string_exp) -> RTRIM(string_exp) * SOUNDEX(string_exp) -> SOUNDEX(string_exp) * SPACE(count) (ODBC 2.0) -> SPACE(count) (ODBC 2.0) * SUBSTRING(string_exp, start, length) -> SUBSTRING(string_exp, start, length) * UCASE(string_exp) -> UPPER(string) * * Numeric * Nearly all function use same parameters, except: * ATAN2 -> ATN2 * TRUNCATE -> ?? */ static SQLRETURN to_native(struct _hdbc *dbc, struct _hstmt *stmt, DSTR *str) { char *d, *s; int nest_syntax = 0; char *buf = tds_dstr_buf(str); /* list of bit, used as stack, is call ? FIXME limites size... */ unsigned long is_calls = 0; int server_scalar; assert(dbc); server_scalar = TDS_IS_MSSQL(dbc->tds_socket) && dbc->tds_socket->conn->product_version >= TDS_MS_VER(7, 0, 0); /* * we can do it because result string will be * not bigger than source string */ d = s = buf; while (*s) { if (*s == '-' || *s == '/') { size_t len_comment = tds_skip_comment(s) - s; memmove(d, s, len_comment); s += len_comment; d += len_comment; continue; } /* TODO: test syntax like "select 1 as [pi]]p)p{?=call]]]]o], 2" on mssql7+ */ if (*s == '"' || *s == '\'' || *s == '[') { size_t len_quote = tds_skip_quoted(s) - s; memmove(d, s, len_quote); s += len_quote; d += len_quote; continue; } if (*s == '{') { char *pcall; while (TDS_ISSPACE(*++s)) continue; pcall = s; /* FIXME if nest_syntax > 0 problems */ if (server_scalar && strncasecmp(pcall, "fn ", 3) == 0) { *d++ = '{'; continue; } if (*pcall == '?') { /* skip spaces after ? */ while (TDS_ISSPACE(*++pcall)) continue; if (*pcall == '=') { while (TDS_ISSPACE(*++pcall)) continue; } else { /* avoid {?call ... syntax */ pcall = s; } } if (strncasecmp(pcall, "call ", 5) != 0) pcall = NULL; if (stmt) stmt->prepared_query_is_rpc = 1; ++nest_syntax; is_calls <<= 1; if (!pcall) { /* assume syntax in the form {type ...} */ while (TDS_ISALPHA(*s)) ++s; while (TDS_ISSPACE(*s)) ++s; } else { if (*s == '?' && stmt) stmt->prepared_query_is_func = 1; memcpy(d, "exec ", 5); d += 5; s = pcall + 5; is_calls |= 1; } } else if (nest_syntax > 0) { /* do not copy close syntax */ if (*s == '}') { --nest_syntax; is_calls >>= 1; ++s; continue; /* convert parenthesis in call to spaces */ } else if ((is_calls & 1) && (*s == '(' || *s == ')')) { *d++ = ' '; s++; } else { *d++ = *s++; } } else {