Skip to content

Commit

Permalink
{177994587} Add support for binding arrays by index
Browse files Browse the repository at this point in the history
Signed-off-by: Salil Chandra <[email protected]>
  • Loading branch information
chands10 committed Jan 22, 2025
1 parent faa452e commit c6162be
Show file tree
Hide file tree
Showing 8 changed files with 425 additions and 81 deletions.
59 changes: 45 additions & 14 deletions cdb2api/cdb2api.c
Original file line number Diff line number Diff line change
Expand Up @@ -5514,17 +5514,10 @@ int cdb2_bind_index(cdb2_hndl_tp *hndl, int index, int type,
}


/* cdb2_bind_array -- bind c array to a parameter name
* name is the variable name we used in the sql
* type is the type of elements to bind ex. CDB2_INTEGER
* varaddr is the array address
* count is the number of items in the array we will bind
* typelen is the size of the elements for integer-arrays sizeof(int32_t or int64_t)
*/
int cdb2_bind_array(cdb2_hndl_tp *hndl, const char *name, cdb2_coltype type, const void *varaddr, size_t count, size_t typelen)
static int cdb2_bind_array_helper(cdb2_hndl_tp *hndl, cdb2_coltype type, const void *varaddr, size_t count, size_t typelen, const char *func)
{
if (count <= 0 || count > CDB2_MAX_BIND_ARRAY) {
sprintf(hndl->errstr, "%s: bad array length:%zd (max:%d)", __func__, count, CDB2_MAX_BIND_ARRAY);
sprintf(hndl->errstr, "%s: bad array length:%zd (max:%d)", func, count, CDB2_MAX_BIND_ARRAY);
return -1;
}

Expand Down Expand Up @@ -5584,16 +5577,11 @@ int cdb2_bind_array(cdb2_hndl_tp *hndl, const char *name, cdb2_coltype type, con
CDB2SQLQUERY__Bindvalue *bindval = malloc(sizeof(CDB2SQLQUERY__Bindvalue));
cdb2__sqlquery__bindvalue__init(bindval);
bindval->type = type;
bindval->varname = (char *)name;
bindval->carray = carray;

hndl->n_bindvars++;
hndl->bindvars = realloc(hndl->bindvars, sizeof(CDB2SQLQUERY__Bindvalue *) * hndl->n_bindvars);
hndl->bindvars[hndl->n_bindvars - 1] = bindval;
if (log_calls)
fprintf(stderr, "%p> cdb2_bind_array(%p, \"%s\", %zu, %s, %p, %zu) = 0\n",
(void *)pthread_self(), hndl, name, count,
cdb2_type_str(type), varaddr, typelen);

return 0;

Expand All @@ -5603,6 +5591,49 @@ int cdb2_bind_array(cdb2_hndl_tp *hndl, const char *name, cdb2_coltype type, con
return -1;
}

/* cdb2_bind_array -- bind c array to a parameter name
* name is the variable name we used in the sql
* type is the type of elements to bind ex. CDB2_INTEGER
* varaddr is the array address
* count is the number of items in the array we will bind
* typelen is the size of the elements for integer-arrays sizeof(int32_t or int64_t)
*/
int cdb2_bind_array(cdb2_hndl_tp *hndl, const char *name, cdb2_coltype type, const void *varaddr, size_t count, size_t typelen)
{
int rc = 0;
rc = cdb2_bind_array_helper(hndl, type, varaddr, count, typelen, __func__);
if (rc)
return rc;

CDB2SQLQUERY__Bindvalue *bindval = hndl->bindvars[hndl->n_bindvars - 1];
bindval->varname = (char *)name;
if (log_calls)
fprintf(stderr, "%p> %s(%p, \"%s\", %zu, %s, %p, %zu) = 0\n",
(void *)pthread_self(), __func__, hndl, name, count,
cdb2_type_str(type), varaddr, typelen);

return rc;
}

int cdb2_bind_array_index(cdb2_hndl_tp *hndl, int index, cdb2_coltype type, const void *varaddr, size_t count, size_t typelen)
{
int rc = 0;
rc = cdb2_bind_array_helper(hndl, type, varaddr, count, typelen, __func__);
if (rc)
return rc;

CDB2SQLQUERY__Bindvalue *bindval = hndl->bindvars[hndl->n_bindvars - 1];
bindval->varname = NULL;
bindval->has_index = 1;
bindval->index = index;
if (log_calls)
fprintf(stderr, "%p> %s(%p, %d, %zu, %s, %p, %zu) = 0\n",
(void *)pthread_self(), __func__, hndl, index, count,
cdb2_type_str(type), varaddr, typelen);

return rc;
}

int cdb2_clearbindings(cdb2_hndl_tp *hndl)
{
if (hndl->is_child_hndl) {
Expand Down
3 changes: 2 additions & 1 deletion cdb2api/cdb2api.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ int cdb2_bind_param(cdb2_hndl_tp *hndl, const char *name, int type,
const void *varaddr, int length);
int cdb2_bind_index(cdb2_hndl_tp *hndl, int index, int type,
const void *varaddr, int length);
int cdb2_bind_array(cdb2_hndl_tp *, const char *, cdb2_coltype, const void *, size_t count, size_t typelen);
int cdb2_bind_array(cdb2_hndl_tp *, const char *, cdb2_coltype, const void *, size_t, size_t);
int cdb2_bind_array_index(cdb2_hndl_tp *, int, cdb2_coltype, const void *, size_t, size_t);
int cdb2_clearbindings(cdb2_hndl_tp *hndl);

const char *cdb2_dbname(cdb2_hndl_tp *hndl);
Expand Down
29 changes: 29 additions & 0 deletions docs/pages/programming/c_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,35 @@ Parameters:
|*typelen*| input | The length of the data type of the array which is being passed in | This should be the sizeof(valueaddr's original type), so 4 if it's a int32, 8 for int64... |
### cdb2_bind_array_index
```
int cdb2_bind_array(cdb2_hndl_tp *hndl, int index, cdb2_coltype type, const void *varaddr, size_t count, size_t typelen)

```
Description:
This routine is used to bind arrays by index in sql statement. The index starts from 1, and increases for every new parameter in the statement. This version of cdb2_bind_* is faster than cdb2_bind_array.
For example:
```c
int arr[10] = {1,2,3,4...};
cdb2_bind_array_index(hndl, 1, CDB2_INTEGER, arr, 10, sizeof(int));
cdb2_run_statement(db, "SELECT * FROM a WHERE i IN CARRAY(@arr)");
```

Parameters:

|Name|Type|Description|Notes|
|---|---|---|--|
|*hndl*| input | cdb2 handle | A previously allocated CDB2 handle |
| *index* | input | The index of replaceable param | The value associated with this pointer should not change between bind and [cdb2_run_statement](#cdb2_run_statement) |
|*type*| input | The type of replaceable param | |
|*valueaddr*| input | The value pointer of replaceable param | The value associated with this pointer should not change between bind and [cdb2_run_statement](#cdb2_run_statement), and for numeric types must be signed. |
|*count*| input | The count of items in the array | |
|*typelen*| input | The length of the data type of the array which is being passed in | This should be the sizeof(valueaddr's original type), so 4 if it's a int32, 8 for int64... |

### cdb2_get_effects
```
int cdb2_get_effects(cdb2_hndl_tp *hndl, cdb2_effects_tp *effects);
Expand Down
4 changes: 4 additions & 0 deletions tests/replay_eventlog.test/fingerprints_freq.exp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
110 57baf721618dee0c3a0d21df32d4a5b3 insert into t1(alltypes_
200 66442322591d17e49d307d91fd1c9db6 update t1 set alltypes_s
1 675711719ff4adb4273c869b82c6a9db select csc2 from sqlite_
1 6b24619bf5b1d9451ca93b596a7f25bb create table carray2 (a
1 71b3096abbf0ee777a855d028ab18341 select count(*) cnt from
1 786a016d5d737d34389e6bc6d35f2d50 select * from carray1 or
1000 7b3aa6d46d54b8a092b8c3e74a1fc7d0 insert into t1( alltype
100 8b048737cee209884c0eb5b86f9815f7 insert into t1(alltypes_
Expand All @@ -19,6 +21,8 @@
500 aefd75efcaf1d7e65205373fc5a09b89 update t1 set alltypes_s
1 b5cfea50b21a7a6db8eb7f28ee128c27 select count(*) cnt from
1 d31abc248f09fd1099a22a5c6f0e895e create table carray1 (a
1 d4f6f8c186c47ce52cfce1d1322fb241 select * from carray2 or
1 de7d90bac2eda4575455da3149ac0fe1 with a as (select rowid,
110 e4510162feae7bd9a746c798ad56027d insert into t1(alltypes_
10 f2c85b80eb883ee3c1eb184a8bca4e4d update t1 set alltypes_u
1 f49bb0b4877aac4df9adb8d4e097e140 select * from t1 order b
Expand Down
3 changes: 3 additions & 0 deletions tests/replay_eventlog.test/runit
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ done

cdb2sql ${CDB2_OPTIONS} ${DBNAME} default "create table t1 { `cat alltypes.csc2 ` }"
cdb2sql ${CDB2_OPTIONS} ${DBNAME} default "create table carray1 (a int, b double, c cstring(32), d longlong, e blob)"
cdb2sql ${CDB2_OPTIONS} ${DBNAME} default "create table carray2 (a int, b double, c cstring(32), d longlong, e blob)"

# following is an error because t2 does not exist, resulting in a
# fingerprint of 00000 so will not ba replayed
Expand Down Expand Up @@ -267,6 +268,7 @@ ${TESTSBUILDDIR}/carray_insert ${DBNAME}

cdb2sql ${CDB2_OPTIONS} ${DBNAME} default "select * from t1 order by alltypes_u_short" > orig.txt
cdb2sql ${CDB2_OPTIONS} ${DBNAME} default "select * from carray1 order by 1" >> orig.txt
cdb2sql ${CDB2_OPTIONS} ${DBNAME} default "select * from carray2 order by 1" >> orig.txt

logflunziped=events.unzipped
if [[ -z "$CLUSTER" ]]; then
Expand Down Expand Up @@ -323,6 +325,7 @@ fi

cdb2sql ${SECONDARY_CDB2_OPTIONS} $SECONDARY_DBNAME default "select * from t1 order by alltypes_u_short" > replayed.txt
cdb2sql ${SECONDARY_CDB2_OPTIONS} $SECONDARY_DBNAME default "select * from carray1 order by 1" >> replayed.txt
cdb2sql ${SECONDARY_CDB2_OPTIONS} $SECONDARY_DBNAME default "select * from carray2 order by 1" >> replayed.txt

success=1

Expand Down
101 changes: 77 additions & 24 deletions tests/tools/carray_insert.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,55 @@

#include <cdb2api.h>

void post_run(cdb2_hndl_tp *db, char *file, int index)
{
int rc;
while ((rc = cdb2_next_record(db)) == CDB2_OK)
;
if (rc != CDB2_OK_DONE) {
fprintf(stderr, "%s:%d cdb2_next_record rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

if ((rc = cdb2_clearbindings(db)) != 0) {
fprintf(stderr, "%s:%d cdb2_clearbindings rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

cdb2_effects_tp effects;
if ((rc = cdb2_get_effects(db, &effects)) != 0) {
fprintf(stderr, "%s:%d cdb2_get_effects rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

char *sql = index ? "select count(*) cnt from carray2" : "select count(*) cnt from carray1";
if ((rc = cdb2_run_statement(db, sql)) != 0) {
fprintf(stderr, "%s:%d cdb2_run_statement rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

if ((rc = cdb2_next_record(db)) != CDB2_OK) {
fprintf(stderr, "%s:%d cdb2_next_record rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

int cnt = *(int64_t *)cdb2_column_value(db, 0);

if ((rc = cdb2_next_record(db)) != CDB2_OK_DONE) {
fprintf(stderr, "%s:%d cdb2_next_record rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

printf("%s:%d num_inserted:%d, count is:%d\n", file, __LINE__, effects.num_inserted, cnt);

if (effects.num_inserted == 5 && cnt == 5) {
printf("%s:%d pass%s\n", file, __LINE__, index ? " index" : "");
} else {
fprintf(stderr, "%s:%d failed%s\n", file, __LINE__, index ? " index" : "");
abort();
}
}

int main(int argc, char *argv[])
{
char *file = basename(__FILE__);
Expand Down Expand Up @@ -72,50 +121,54 @@ int main(int argc, char *argv[])
fprintf(stderr, "%s:%d cdb2_run_statement rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}
while ((rc = cdb2_next_record(db)) == CDB2_OK)
;
if (rc != CDB2_OK_DONE) {
fprintf(stderr, "%s:%d cdb2_next_record rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

if ((rc = cdb2_clearbindings(db)) != 0) {
fprintf(stderr, "%s:%d cdb2_clearbindings rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
post_run(db, file, 0);

if ((rc = cdb2_bind_array_index(db, 1, CDB2_INTEGER, a, sizeof(a) / sizeof(a[0]), sizeof(a[0]))) != 0) {
fprintf(stderr, "%s:%d cdb2_bind_array_index rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

cdb2_effects_tp effects;
if ((rc = cdb2_get_effects(db, &effects)) != 0) {
fprintf(stderr, "%s:%d cdb2_get_effects rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
if ((rc = cdb2_bind_array_index(db, 2, CDB2_REAL, b, sizeof(b) / sizeof(b[0]), 0)) != 0) {
fprintf(stderr, "%s:%d cdb2_bind_array_index rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

if ((rc = cdb2_run_statement(db, "select count(*) cnt from carray1")) != 0) {
fprintf(stderr, "%s:%d cdb2_run_statement rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
if ((rc = cdb2_bind_array_index(db, 3, CDB2_CSTRING, c, sizeof(c) / sizeof(c[0]), 0)) != 0) {
fprintf(stderr, "%s:%d cdb2_bind_array_index rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

if ((rc = cdb2_next_record(db)) != CDB2_OK) {
fprintf(stderr, "%s:%d cdb2_next_record rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
if ((rc = cdb2_bind_array_index(db, 4, CDB2_INTEGER, d, sizeof(d) / sizeof(d[0]), sizeof(d[0]))) != 0) {
fprintf(stderr, "%s:%d cdb2_bind_array_index rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

int cnt = *(int64_t *)cdb2_column_value(db, 0);

if ((rc = cdb2_next_record(db)) != CDB2_OK_DONE) {
fprintf(stderr, "%s:%d cdb2_next_record rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
if ((rc = cdb2_bind_array_index(db, 5, CDB2_BLOB, e, sizeof(e) / sizeof(e[0]), 0)) != 0) {
fprintf(stderr, "%s:%d cdb2_bind_array_index rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

printf("%s:%d num_inserted:%d, count is:%d\n", file, __LINE__, effects.num_inserted, cnt);
rc = cdb2_run_statement(db, "with a as (select rowid, value aa from carray(?)), "
"b as (select rowid, value bb from carray(?)), "
"c as (select rowid, value cc from carray(?)), "
"d as (select rowid, value dd from carray(?)), "
"e as (select rowid, value ee from carray(?)) "
"insert into carray2 select aa, bb, cc, dd, ee "
"from a "
"join b on b.rowid = a.rowid "
"join c on c.rowid = a.rowid "
"join d on d.rowid = a.rowid "
"join e on e.rowid = a.rowid "
);

if (effects.num_inserted == 5 && cnt == 5) {
printf("%s:%d pass\n", file, __LINE__);
} else {
fprintf(stderr, "%s:%d failed\n", file, __LINE__);
if (rc != 0) {
fprintf(stderr, "%s:%d cdb2_run_statement rc=%d:%s\n", file, __LINE__, rc, cdb2_errstr(db));
abort();
}

post_run(db, file, 1);

cdb2_close(db);
return 0;
}
Loading

0 comments on commit c6162be

Please sign in to comment.