// FIXME: use ct_setparam to avoid copying data void command::set_params(sybase_query &query, const QoreListNode *args, ExceptionSink *xsink) { unsigned nparams = query.param_list.size(); for (unsigned i = 0; i < nparams; ++i) { if (query.param_list[i] == 'd') continue; const AbstractQoreNode *val = args ? args->retrieve_entry(i) : NULL; CS_DATAFMT datafmt; memset(&datafmt, 0, sizeof(datafmt)); datafmt.status = CS_INPUTVALUE; datafmt.namelen = CS_NULLTERM; sprintf(datafmt.name, "@par%d", int(i + 1)); datafmt.maxlength = CS_UNUSED; datafmt.count = 1; CS_RETCODE err = CS_FAIL; if (!val || is_null(val) || is_nothing(val)) { #ifdef FREETDS // it seems to be necessary to specify a type like // this to get a null value to be bound with freetds datafmt.datatype = CS_CHAR_TYPE; datafmt.format = CS_FMT_NULLTERM; datafmt.maxlength = 1; #endif // SQL NULL value err = ct_param(m_cmd, &datafmt, 0, CS_UNUSED, -1); if (err != CS_SUCCEED) { m_conn.do_exception(xsink, "DBI:SYBASE:EXEC-ERROR", "ct_param() for 'null' failed for parameter %u with error %d", i, (int)err); return; } continue; } qore_type_t ntype = val ? val->getType() : 0; switch (ntype) { case NT_STRING: { const QoreStringNode *str = reinterpret_cast<const QoreStringNode *>(val); // ensure we bind with the proper encoding for the connection TempEncodingHelper s(str, m_conn.getEncoding(), xsink); if (!s) throw ss::Error("DBI:SYBASE:EXEC-ERROR", "encoding"); int slen = s->strlen(); datafmt.datatype = CS_CHAR_TYPE; datafmt.format = CS_FMT_NULLTERM; // NOTE: setting large sizes here like 2GB works for sybase ctlib, // not for freetds datafmt.maxlength = slen + 1; err = ct_param(m_cmd, &datafmt, (CS_VOID*)s->getBuffer(), slen, 0); break; } case NT_NUMBER: { QoreStringValueHelper vh(val); int slen = vh->strlen(); datafmt.datatype = CS_CHAR_TYPE; datafmt.format = CS_FMT_NULLTERM; datafmt.maxlength = slen + 1; err = ct_param(m_cmd, &datafmt, (CS_VOID *)vh->getBuffer(), slen, 0); break; } case NT_DATE: { const DateTimeNode *date = reinterpret_cast<const DateTimeNode *>(val); CS_DATETIME dt; ss::Conversions conv; if (conv.DateTime_to_DATETIME(date, dt, xsink)) throw ss::Error("DBI:SYBASE:EXEC-ERROR", "can't convert date"); datafmt.datatype = CS_DATETIME_TYPE; err = ct_param(m_cmd, &datafmt, &dt, sizeof(dt), 0); break; } case NT_INT: { #ifdef CS_BIGINT_TYPE datafmt.datatype = CS_BIGINT_TYPE; err = ct_param(m_cmd, &datafmt, &(const_cast<QoreBigIntNode *>(reinterpret_cast<const QoreBigIntNode *>(val))->val), sizeof(int64), 0); #else int64 ival = reinterpret_cast<const QoreBigIntNode *>(val)->val; // if it's a 32-bit integer, bind as integer if (ival <= 2147483647 && ival >= -2147483647) { datafmt.datatype = CS_INT_TYPE; CS_INT vint = ival; err = ct_param(m_cmd, &datafmt, &vint, sizeof(CS_INT), 0); } else { // bind as float CS_FLOAT fval = ival; datafmt.datatype = CS_FLOAT_TYPE; err = ct_param(m_cmd, &datafmt, &fval, sizeof(CS_FLOAT), 0); } #endif break; } case NT_BOOLEAN: { // Seems mssql doesn't like CS_BIT_TYPE for some reason. // Replacing by CS_INT_TYPE helps // // The "BIT" code is supposed to be like this: // datafmt.datatype = CS_BIT_TYPE; // err = ct_param(m_cmd, &datafmt, &bval, sizeof(bval), 0); // ... but it doesn't work CS_BIT bval = reinterpret_cast<const QoreBoolNode *>(val)->getValue(); datafmt.datatype = CS_INT_TYPE; int64 ival = bval ? 1 : 0; err = ct_param(m_cmd, &datafmt, &ival, sizeof(ival), 0); break; } case NT_FLOAT: { CS_FLOAT fval = reinterpret_cast<const QoreFloatNode *>(val)->f; datafmt.datatype = CS_FLOAT_TYPE; err = ct_param(m_cmd, &datafmt, &fval, sizeof(CS_FLOAT), 0); break; } case NT_BINARY: { const BinaryNode *b = reinterpret_cast<const BinaryNode *>(val); datafmt.datatype = CS_BINARY_TYPE; datafmt.maxlength = b->size(); datafmt.count = 1; err = ct_param(m_cmd, &datafmt, (void *)b->getPtr(), b->size(), 0); break; } default: m_conn.do_exception(xsink, "DBI:SYBASE:BIND-ERROR", "do not know how to bind values of type '%s'", val->getTypeName()); return; } // switch(ntype) if (err != CS_SUCCEED) { m_conn.do_exception(xsink, "DBI:SYBASE:EXEC-ERROR", "ct_param() for binary parameter %u failed with error", i, (int)err); } } }
static PyObject *CS_COMMAND_ct_param(CS_COMMANDObj *self, PyObject *args) { PyObject *obj; CS_RETCODE status; if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; if (self->cmd == NULL) { PyErr_SetString(PyExc_TypeError, "CS_COMMAND has been dropped"); return NULL; } /* FIXME: Need to handle CS_UPDATECOL variant */ if (DataBuf_Check(obj)) { DataBufObj *databuf = (DataBufObj *)obj; /* PyErr_Clear(); */ SY_CONN_BEGIN_THREADS(self->conn); status = ct_param(self->cmd, &databuf->fmt, databuf->buff, databuf->copied[0], databuf->indicator[0]); SY_CONN_END_THREADS(self->conn); if (self->debug) { debug_msg("ct_param(cmd%d, &databuf%d->fmt=", self->serial, databuf->serial); datafmt_debug(&databuf->fmt); debug_msg(", databuf%d->buff, %d, %d) -> %s\n", databuf->serial, (int)databuf->copied[0], databuf->indicator[0], value_str(VAL_STATUS, status)); } if (PyErr_Occurred()) return NULL; } else if (CS_DATAFMT_Check(obj)) { CS_DATAFMTObj *datafmt = (CS_DATAFMTObj *)obj; /* PyErr_Clear(); */ SY_CONN_BEGIN_THREADS(self->conn); status = ct_param(self->cmd, &datafmt->fmt, NULL, CS_UNUSED, (CS_SMALLINT)CS_UNUSED); SY_CONN_END_THREADS(self->conn); if (self->debug) { debug_msg("ct_param(cmd%d, &fmt=", self->serial); datafmt_debug(&datafmt->fmt); debug_msg(", NULL, CS_UNUSED, CS_UNUSED) -> %s\n", value_str(VAL_STATUS, status)); } if (PyErr_Occurred()) return NULL; } else { PyErr_SetString(PyExc_TypeError, "expect CS_DATAFMT or DataBuf"); return NULL; } return PyInt_FromLong(status); }
static int insert_test(CS_CONNECTION *conn, CS_COMMAND *cmd, int useNames) { CS_CONTEXT *ctx; CS_RETCODE ret; CS_INT res_type; CS_DATAFMT datafmt; CS_DATAFMT srcfmt; CS_DATAFMT destfmt; CS_INT intvar; CS_FLOAT floatvar; CS_MONEY moneyvar; CS_DATEREC datevar; char moneystring[10]; char dummy_name[30]; char dummy_name2[20]; CS_INT destlen; /* clear table */ run_command(cmd, "delete #ctparam_lang"); /* * Assign values to the variables used for parameter passing. */ intvar = 2; floatvar = 0.12; strcpy(dummy_name, "joe blow"); strcpy(dummy_name2, ""); strcpy(moneystring, "300.90"); /* * Clear and setup the CS_DATAFMT structures used to convert datatypes. */ memset(&srcfmt, 0, sizeof(CS_DATAFMT)); srcfmt.datatype = CS_CHAR_TYPE; srcfmt.maxlength = (CS_INT)strlen(moneystring); srcfmt.precision = 5; srcfmt.scale = 2; srcfmt.locale = NULL; memset(&destfmt, 0, sizeof(CS_DATAFMT)); destfmt.datatype = CS_MONEY_TYPE; destfmt.maxlength = sizeof(CS_MONEY); destfmt.precision = 5; destfmt.scale = 2; destfmt.locale = NULL; /* * Convert the string representing the money value * to a CS_MONEY variable. Since this routine does not have the * context handle, we use the property functions to get it. */ if ((ret = ct_cmd_props(cmd, CS_GET, CS_PARENT_HANDLE, &conn, CS_UNUSED, NULL)) != CS_SUCCEED) { fprintf(stderr, "ct_cmd_props() failed\n"); return 1; } if ((ret = ct_con_props(conn, CS_GET, CS_PARENT_HANDLE, &ctx, CS_UNUSED, NULL)) != CS_SUCCEED) { fprintf(stderr, "ct_con_props() failed\n"); return 1; } ret = cs_convert(ctx, &srcfmt, (CS_VOID *) moneystring, &destfmt, &moneyvar, &destlen); if (ret != CS_SUCCEED) { fprintf(stderr, "cs_convert() failed\n"); return 1; } /* * create the command */ if ((ret = ct_command(cmd, CS_LANG_CMD, query, (CS_INT)strlen(query), CS_UNUSED)) != CS_SUCCEED) { fprintf(stderr, "ct_command(CS_LANG_CMD) failed\n"); return 1; } /* * Clear and setup the CS_DATAFMT structure, then pass * each of the parameters for the query. */ memset(&datafmt, 0, sizeof(datafmt)); if (useNames) strcpy(datafmt.name, "@in1"); else datafmt.name[0] = 0; datafmt.maxlength = 255; datafmt.namelen = CS_NULLTERM; datafmt.datatype = CS_CHAR_TYPE; datafmt.status = CS_INPUTVALUE; /* * The character string variable is filled in by the RPC so pass NULL * for the data 0 for data length, and -1 for the indicator arguments. */ ret = ct_param(cmd, &datafmt, dummy_name, (CS_INT)strlen(dummy_name), 0); if (CS_SUCCEED != ret) { fprintf(stderr, "ct_param(char) failed\n"); return 1; } if (useNames) strcpy(datafmt.name, "@in2"); else datafmt.name[0] = 0; datafmt.maxlength = 255; datafmt.namelen = CS_NULLTERM; datafmt.datatype = CS_CHAR_TYPE; datafmt.status = CS_INPUTVALUE; ret = ct_param(cmd, &datafmt, dummy_name2, (CS_INT)strlen(dummy_name2), 0); if (CS_SUCCEED != ret) { fprintf(stderr, "ct_param(char) failed\n"); return 1; } if (useNames) strcpy(datafmt.name, "@in3"); else datafmt.name[0] = 0; datafmt.namelen = CS_NULLTERM; datafmt.datatype = CS_INT_TYPE; datafmt.status = CS_INPUTVALUE; ret = ct_param(cmd, &datafmt, (CS_VOID *) & intvar, CS_SIZEOF(CS_INT), 0); if (CS_SUCCEED != ret) { fprintf(stderr, "ct_param(int) failed\n"); return 1; } if (useNames) strcpy(datafmt.name, "@moneyval"); else datafmt.name[0] = 0; datafmt.namelen = CS_NULLTERM; datafmt.datatype = CS_MONEY_TYPE; datafmt.status = CS_INPUTVALUE; ret = ct_param(cmd, &datafmt, (CS_VOID *) & moneyvar, CS_SIZEOF(CS_MONEY), 0); if (CS_SUCCEED != ret) { fprintf(stderr, "ct_param(money) failed\n"); return 1; } if (useNames) strcpy(datafmt.name, "@dateval"); else datafmt.name[0] = 0; datafmt.namelen = CS_NULLTERM; datafmt.datatype = CS_DATETIME_TYPE; datafmt.status = CS_INPUTVALUE; memset(&datevar, 0, sizeof(CS_DATEREC)); datevar.dateyear = 2003; datevar.datemonth = 2; datevar.datedmonth = 1; ret = ct_param(cmd, &datafmt, &datevar, 0, 0); if (CS_SUCCEED != ret) { fprintf(stderr, "ct_param(datetime) failed"); return 1; } if (useNames) strcpy(datafmt.name, "@floatval"); else datafmt.name[0] = 0; datafmt.namelen = CS_NULLTERM; datafmt.datatype = CS_FLOAT_TYPE; datafmt.status = CS_INPUTVALUE; ret = ct_param(cmd, &datafmt, &floatvar, 0, 0); if (CS_SUCCEED != ret) { fprintf(stderr, "ct_param(float) failed"); return 1; } /* * Send the command to the server */ if (ct_send(cmd) != CS_SUCCEED) { fprintf(stderr, "ct_send(CS_LANG_CMD) failed\n"); return 1; } /* * Process the results. */ while ((ret = ct_results(cmd, &res_type)) == CS_SUCCEED) { switch ((int) res_type) { case CS_CMD_SUCCEED: case CS_CMD_DONE: { CS_INT rowsAffected=0; ct_res_info(cmd, CS_ROW_COUNT, &rowsAffected, CS_UNUSED, NULL); if (1 != rowsAffected) fprintf(stderr, "insert touched %d rows instead of 1\n", rowsAffected); } break; case CS_CMD_FAIL: /* * The server encountered an error while * processing our command. */ fprintf(stderr, "ct_results returned CS_CMD_FAIL.\n"); break; case CS_STATUS_RESULT: /* * The server encountered an error while * processing our command. */ fprintf(stderr, "ct_results returned CS_STATUS_RESULT.\n"); break; default: /* * We got something unexpected. */ fprintf(stderr, "ct_results returned unexpected result type %d\n", res_type); return 1; } } if (ret != CS_END_RESULTS) fprintf(stderr, "ct_results returned unexpected result %d.\n", (int) ret); /* test row inserted */ ret = run_command(cmd, "if not exists(select * from #ctparam_lang where name = 'joe blow' and name2 is not null and age = 2) select 1"); if (ret != CS_SUCCEED) { fprintf(stderr, "check row inserted failed\n"); exit(1); } return 0; }