maria-discuss team mailing list archive
-
maria-discuss team
-
Mailing list archive
-
Message #06552
howto c-connect bindings
hi
I'm working with|mariadb|and|c-connect|prepared statements and run into
crashes executing them once a while. i so addressed my problem to
stakeoverflow
<https://stackoverflow.com/questions/76170354/mariadb-howto-c-connect-bindings>
hoping to get more information for binding programs data structure to db
interface.
i did get an answer. but this answer does not go inline with your
documentation
<https://mariadb.com/kb/en/mariadb-connectorc-data-structures/#mysql_bind>.
i so do have the option to follow your documentation or use the answer
and run into crashes in either way. you might ask why i'm not just going
with your documentation? your documentation is far to thin to get a
reliable idea how bind structure is used and i do get proofed this by
crashes. second i played with <my_bool * is_nulll Pointer which
indicates if column is NULL (not used for parameters)> for parameters
and behavior was not as documented.
this is my motivation to bring my problem to this mailing list hopping
someone can point me to a documentation i can rely on.
i found a short and useful documentation in mysql with permissible in
and out types
<https://dev.mysql.com/doc/c-api/8.0/en/c-api-prepared-statement-type-codes.html>
and statement data structures
<https://dev.mysql.com/doc/c-api/8.0/en/c-api-prepared-statement-data-structures.html>.
can i use these informations to build 2 test applications one focusing
on parameter (attachment) one focusing on result?
currently i implemented MariaPrepUpd.c using mariadb documentation. i
felt like flying blind and ended up in crashes - once a while. do you
think i could use mysql documentation for improving bindings? or do you
have a better option?
(i studied your bulk example
<https://mariadb.com/kb/en/bulk-insert-row-wise-binding/>. i even was
using this example as base for first try an hit the wall by using
STMT_INDICATOR_NTS. i then learned my problem is not just the example
using STMT_ATTR_ARRAY_SIZE = 1.)
my goal is to have a version of MariaPrepUpd.c i can use for any
application for iteration 1 to n.
thank you for short answer.
have a great day.
juerg(=george) oehler
/*------v---v--------v----------------------------------------------------------
* @(#) Maria DB test for prepared statements focus on parameters
* @(#) cPgmMain 2022-02 by juerg.oehler@xxxxxxxxxxx
*------------------------------------------------------------------------------
* compile: first set your HOST, DB, USER, PWD
* CFLAGS =-Wall -g -O2 -D _XOPEN_SOURCE=700 -D _GNU_SOURCE
* LDLIBS =-lmysqlclient
* docs: no
* refs: https://mariadb.com/kb/en/mariadb-connector-c/
* https://mariadb.com/kb/en/connectorc-types-and-definitions/
* comment: most simple application as a howto use prepared statement interface
* focused on parameter only.
* statments:
* create table t_test (number integer primary key, name varchar(30), stamp datetime, birthtm datetime(6), price float, precise double, smally smallint, tiny tinyint unsigned, epoch bigint unsigned, x509cert varchar(3072), picture blob(65535)) comment 'test table mariadb test programs';
* select number, name, stamp, birthtm, price, precise, smally, tiny, epoch, length (x509cert), length (picture) from t_test;
* history:
*------------------------------------------------------------------------------
* this program is distributed under GPL license in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Library General Public License for more details at
* free software foundation.
*
* (c) Copyright 2022- by OIS-net.org
---------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <mysql/mysql.h>
typedef struct s_dbinfo { // MARIADB_CONNECTION
char *host; // HOST
int port; // PORT
char *user; // USER
} dbinfo; // see https://mariadb.com/kb/en/mariadb_get_infov
typedef struct test { // input / output buffer structure
int number; // -2147483648 to 2147483647
char numberI; // null indicator
char name[31]; // db buffer + EOS
char nameI;
char stamp[31]; // db buffer + EOS
char stampI;
MYSQL_TIME birthtm; // datetime as datastructure
char birthtmI;
float price; // 6 digit guaranteed precision IEEE 754
char priceI;
double precise; // 15 digit guaranteed precision IEEE 754
char preciseI;
short smally; // -32768 to 32767
char smallyI;
unsigned char tiny; // 0 to 255
char tinyI;
unsigned long long epoch; // -2^63 to 2^63-1
char epochI;
char *x509cert; // allocated on demand EOS terminated
char x509certI;
char *picture; // allocated on demand not EOS terminated
char pictureI;
unsigned long pictureL;
} test;
/*------------------------------------------------------------------------------
* begin coding
- this is the shortest way to show problems using goto i never use elsewhere
- a more complete test is MysqlDynamic please ask for code if interested
- compile it with CFLAGS =-Wall -g -O2 -D _XOPEN_SOURCE=700 -D _GNU_SOURCE
- link it with LDLIBS =-lmysqlclient
*--------------------------------------------------------------------------- */
int main (int argc, char *argv[]) {
dbinfo dbi;
int sver, cver;
unsigned int errsav;
MYSQL *con = 0;
MYSQL_STMT *stmt = 0;
MYSQL_BIND *bnd = 0;
my_ulonglong done;
test data;
int bndvars, i;
if (! (con = mysql_init (NULL))) {
printf ("cant't initialize mariadb\n");
exit (1);
}
mysql_real_connect (con, "localhost", "testA", "Atest", "test", 0, NULL, 0);
if ((errsav = mysql_errno (con))) {
printf ("can't connect to test err:%d <%s>\n", errsav, mysql_error (con));
exit (2);
}
mariadb_get_infov (con, MARIADB_CONNECTION_HOST, (void *)&dbi.host);
mariadb_get_infov (con, MARIADB_CONNECTION_USER, (void *)&dbi.user);
printf ("connected on %s to db test by %s\n", dbi.host, dbi.user);
sver = mysql_get_server_version (con);
cver = mysql_get_client_version ();
printf ("mariadb server ver:<%d>, client ver:<%d>\n", sver, cver);
/*--------------------------------------------------------------------------
* set data - yea - it's stupid - but short
* data record with num will be updated
*----------------------------------------------------------------------- */
memset (&data, 0, sizeof (data));
data.number = 87;
strcpy (data.name, "just a test");
strcpy (data.stamp, "2002-03-26");
data.birthtm.year = 2001; data.birthtm.month = 2; data.birthtm.day = 20;
data.birthtm.hour = 16; data.birthtm.minute = 45; data.birthtm.second =3;
data.birthtm.second_part = 455;
data.birthtmI = 1;
data.price = -234.345;
data.precise = 198.77930890098;
data.preciseI = 1;
data.smally = 19458;
data.tiny = 'A';
data.epoch = time( NULL );
data.x509cert = malloc (10); memset(data.x509cert, 0, 10); // short cut
data.x509certI = 1;
data.picture = malloc (10); memset(data.picture, 0, 10); // short cut
data.pictureI = 1;
/*--------------------------------------------------------------------------
* prepare .. currently an update
*----------------------------------------------------------------------- */
stmt = mysql_stmt_init (con);
if (!stmt) {
puts ("mysql_stmt_init() out of memory");
goto end;
}
char query[] = "update t_test set name = ?, stamp = ?, birthtm = ?, price = ?, precise = ?, smally = ?, tiny = ?, epoch = ?, x509cert = ? where number = ?";
bndvars = 10;
if (mysql_stmt_prepare (stmt, query, -1)) {
errsav = mysql_stmt_errno (stmt);
printf ("prepare <%s> failed err:%d <%s>\n",
query, errsav, mysql_stmt_error (stmt));
goto end;
}
i = sizeof (MYSQL_BIND) * bndvars;
bnd = malloc (i);
if (!bnd) {
errsav = errno;
printf ("can^t malloc bnd err:%d <%s>\n", errsav, strerror (errsav));
errsav = errno;
goto end;
}
memset (bnd, 0, i);
bnd[0].buffer_type = MYSQL_TYPE_STRING;
bnd[0].buffer = &data.name;
bnd[0].is_null_value = data.nameI;
bnd[0].length_value = (unsigned long) strlen (data.name);
bnd[1].buffer_type = MYSQL_TYPE_STRING;
bnd[1].buffer = &data.stamp;
bnd[1].is_null_value = data.stampI;
bnd[1].length_value = (unsigned long) strlen (data.stamp);
bnd[2].buffer_type = MYSQL_TYPE_DATETIME;
bnd[2].buffer = &data.birthtm;
bnd[2].is_null_value = data.birthtmI;
bnd[3].buffer_type = MYSQL_TYPE_FLOAT;
bnd[3].buffer = &data.price;
bnd[3].is_null_value = data.priceI;
bnd[3].is_unsigned = 0;
bnd[4].buffer_type = MYSQL_TYPE_DOUBLE;
bnd[4].buffer = &data.precise;
bnd[4].is_null_value = data.preciseI;
bnd[4].is_unsigned = 0;
bnd[5].buffer_type = MYSQL_TYPE_SHORT;
bnd[5].buffer = &data.smally;
bnd[5].is_null_value = data.smallyI;
bnd[5].is_unsigned = 0;
bnd[6].buffer_type = MYSQL_TYPE_TINY;
bnd[6].buffer = &data.tiny;
bnd[6].is_null_value = data.tinyI;
bnd[6].is_unsigned = 1;
bnd[7].buffer_type = MYSQL_TYPE_LONGLONG;
bnd[7].buffer = &data.epoch;
bnd[7].is_null_value = data.epochI;
bnd[7].is_unsigned = 1;
bnd[8].buffer_type = MYSQL_TYPE_STRING;
bnd[8].buffer = &data.x509cert;
bnd[8].is_null_value = data.x509certI;
bnd[8].length_value = (unsigned long) strlen (data.x509cert);
bnd[9].buffer_type = MYSQL_TYPE_LONG;
bnd[9].buffer = &data.number;
bnd[9].is_null_value = data.numberI;
bnd[9].is_unsigned = 0;
if (mysql_stmt_bind_param (stmt, bnd)) {
errsav = mysql_stmt_errno (stmt);
fprintf (stderr, "bind param failed err:%d <%s>\n",
errsav, mysql_stmt_error (stmt));
goto end;
}
/*--------------------------------------------------------------------------
* update database record
*----------------------------------------------------------------------- */
if (mysql_stmt_execute (stmt)) {
errsav = mysql_stmt_errno (stmt);
fprintf (stderr, "execute failed err:%d <%s>\n",
errsav, mysql_stmt_error (stmt));
goto end;
}
done = mysql_stmt_affected_rows (stmt);
if (done) {
printf ("%llu records updated\n", done);
if (mysql_commit (con)) {
errsav = mysql_errno (con);
fprintf (stderr, "commit failed err:%d <%s>\n",
errsav, mysql_error (con));
}
} else {
puts ("no records updated");
}
end:
/*--------------------------------------------------------------------------
* shoot down
*----------------------------------------------------------------------- */
if (bnd) { free (bnd); }
if (stmt) { mysql_stmt_close (stmt); }
if (con) { mysql_close (con); }
puts ("i'm done");
}