int main(int argc, char *argv[]) { LOGINREC *login; DBPROCESS *dbproc; int i; DBINT rowint; DBCHAR rowchar[2]; DBCHAR rowdate[32]; DBINT rowtype; DBINT computeint; DBCHAR computedate[32]; set_malloc_options(); read_login_info(argc, argv); fprintf(stdout, "Starting %s\n", argv[0]); /* Fortify_EnterScope(); */ dbinit(); dberrhandle(syb_err_handler); dbmsghandle(syb_msg_handler); fprintf(stdout, "About to logon\n"); login = dblogin(); DBSETLPWD(login, PASSWORD); DBSETLUSER(login, USER); DBSETLAPP(login, "t0023"); fprintf(stdout, "About to open\n"); dbproc = dbopen(login, SERVER); if (strlen(DATABASE)) dbuse(dbproc, DATABASE); dbloginfree(login); if (dbproc != NULL) { TDSSOCKET *tds = dbproc->tds_socket; if (TDS_IS_MSSQL(tds) && tds->conn->product_version >= TDS_MS_VER(11, 0, 0)) { fputs("Skipping COMPUTE tests with MS SQL 2012+.\n", stderr); return 77; } } fprintf(stdout, "creating table\n"); sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } fprintf(stdout, "insert\n"); sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } sql_cmd(dbproc); dbsqlexec(dbproc); while (dbresults(dbproc) == SUCCEED) { /* nop */ } fprintf(stdout, "select\n"); sql_cmd(dbproc); dbsqlexec(dbproc); if (dbresults(dbproc) != SUCCEED) { failed = 1; fprintf(stdout, "Was expecting a result set.\n"); exit(1); } for (i = 1; i <= dbnumcols(dbproc); i++) printf("col %d is %s\n", i, dbcolname(dbproc, i)); fprintf(stdout, "binding row columns\n"); if (SUCCEED != dbbind(dbproc, 1, INTBIND, 0, (BYTE *) & rowint)) { failed = 1; fprintf(stderr, "Had problem with bind col1\n"); abort(); } if (SUCCEED != dbbind(dbproc, 2, STRINGBIND, 0, (BYTE *) rowchar)) { failed = 1; fprintf(stderr, "Had problem with bind col2\n"); abort(); } if (SUCCEED != dbbind(dbproc, 3, STRINGBIND, 0, (BYTE *) rowdate)) { failed = 1; fprintf(stderr, "Had problem with bind col3\n"); abort(); } fprintf(stdout, "testing compute clause 1\n"); if (dbnumalts(dbproc, 1) != 1) { failed = 1; fprintf(stderr, "Had problem with dbnumalts 1\n"); abort(); } if (dbalttype(dbproc, 1, 1) != SYBINT4) { failed = 1; fprintf(stderr, "Had problem with dbalttype 1, 1\n"); abort(); } if (dbaltcolid(dbproc, 1, 1) != 1) { failed = 1; fprintf(stderr, "Had problem with dbaltcolid 1, 1\n"); abort(); } if (dbaltop(dbproc, 1, 1) != SYBAOPSUM) { failed = 1; fprintf(stderr, "Had problem with dbaltop 1, 1\n"); abort(); } if (SUCCEED != dbaltbind(dbproc, 1, 1, INTBIND, 0, (BYTE *) & computeint)) { failed = 1; fprintf(stderr, "Had problem with dbaltbind 1, 1\n"); abort(); } fprintf(stdout, "testing compute clause 2\n"); if (dbnumalts(dbproc, 2) != 1) { failed = 1; fprintf(stderr, "Had problem with dbnumalts 2\n"); abort(); } if (dbalttype(dbproc, 2, 1) != SYBDATETIME) { failed = 1; fprintf(stderr, "Had problem with dbalttype 2, 1\n"); abort(); } if (dbaltcolid(dbproc, 2, 1) != 3) { failed = 1; fprintf(stderr, "Had problem with dbaltcolid 2, 1\n"); abort(); } if (dbaltop(dbproc, 2, 1) != SYBAOPMAX) { failed = 1; fprintf(stderr, "Had problem with dbaltop 2, 1\n"); abort(); } if (SUCCEED != dbaltbind(dbproc, 2, 1, STRINGBIND, -1, (BYTE *) computedate)) { failed = 1; fprintf(stderr, "Had problem with dbaltbind 2, 1\n"); abort(); } while ((rowtype = dbnextrow(dbproc)) != NO_MORE_ROWS) { if (rowtype == REG_ROW) { printf("gotten a regular row\n"); } if (rowtype == 1) { printf("gotten a compute row for clause 1\n"); printf("value of sum(col1) = %d\n", computeint); } if (rowtype == 2) { printf("gotten a compute row for clause 2\n"); printf("value of max(col3) = %s\n", computedate); } } dbexit(); fprintf(stdout, "%s %s\n", __FILE__, (failed ? "failed!" : "OK")); return failed ? 1 : 0; }
/* * 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 {