| 1413 | } |
| 1414 | |
| 1415 | int process_bind(const char *sql) |
| 1416 | { |
| 1417 | if (strncasecmp(sql, "@bind", 5) != 0) |
| 1418 | return process_escape(sql); |
| 1419 | |
| 1420 | const char *copy_sql = sql; |
| 1421 | verbose_print("setting bind parameter\n"); |
| 1422 | //@bind BINDTYPE parameter value |
| 1423 | sql += 5; |
| 1424 | |
| 1425 | int type = get_type(&sql); |
| 1426 | if (type < 0 || !isspace(*sql)) { |
| 1427 | fprintf(stderr, "Usage: @bind <type> <paramname> <value>, with type " |
| 1428 | "one of the following:\n" |
| 1429 | "CDB2_{INTEGER,REAL,CSTRING,BLOB,DATETIME[,US]" |
| 1430 | // uncomment when supported: ",INTERVAL[YM,DS,DSUS]" |
| 1431 | "}\n"); |
| 1432 | fprintf(stderr, "[%s] rc %d\n", copy_sql, type); |
| 1433 | return type; |
| 1434 | } |
| 1435 | |
| 1436 | char *parameter = get_parameter(&sql); |
| 1437 | if (parameter == NULL) { |
| 1438 | fprintf(stderr, "[%s] rc -1: Parameter name expected after type\n", |
| 1439 | copy_sql); |
| 1440 | return -1; |
| 1441 | } |
| 1442 | |
| 1443 | int length; |
| 1444 | int rc = 0; |
| 1445 | void *value = get_val(&sql, type, &length); |
| 1446 | if (!value) { |
| 1447 | fprintf(stderr, "[%s] rc -1: Value expected after parameter\n", |
| 1448 | copy_sql); |
| 1449 | return -1; |
| 1450 | } |
| 1451 | |
| 1452 | if (debug_trace) |
| 1453 | fprintf(stderr, "binding: type %d, param %s, value %s\n", type, |
| 1454 | parameter, sql /* sql now points to the actual value. */); |
| 1455 | if (isdigit(parameter[0])) { |
| 1456 | int index = atoi(parameter); |
| 1457 | if (index <= 0) |
| 1458 | return -1; |
| 1459 | rc = cdb2_bind_index(cdb2h, index, type, value, length); |
| 1460 | } else { |
| 1461 | rc = cdb2_bind_param(cdb2h, parameter, type, value, length); |
| 1462 | /* we have to leak parameter here -- freeing breaks the bind */ |
| 1463 | } |
| 1464 | return rc; |
| 1465 | } |
| 1466 | |
| 1467 | static int run_statement(const char *sql, int ntypes, int *types, |
| 1468 | int *start_time, int *run_time) |
no test coverage detected