Skip to content

Instantly share code, notes, and snippets.

@kubo
Created June 28, 2021 07:03
Show Gist options
  • Save kubo/0b63c8148c4a77f3f9f9c21194c78d47 to your computer and use it in GitHub Desktop.
Save kubo/0b63c8148c4a77f3f9f9c21194c78d47 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <oci.h>
#include <xmlproc.h>
#define CHARSET_ID_UTF8 873
#define chke(func) do { \
sword rv = func; \
fprintf(stderr, "%s => %d\n", #func, rv); \
if (rv == OCI_ERROR) { \
sb4 errcode; \
char errmsg[OCI_ERROR_MAXMSG_SIZE]; \
OCIErrorGet(envhp, 1, NULL, &errcode, (OraText*)errmsg, sizeof(errmsg), OCI_HTYPE_ENV); \
fprintf(stderr, " %s\n", errmsg); \
} \
} while (0)
#define chk(func) do { \
sword rv = func; \
fprintf(stderr, "%s => %d\n", #func, rv); \
if (rv == OCI_ERROR) { \
sb4 errcode; \
char errmsg[OCI_ERROR_MAXMSG_SIZE]; \
OCIErrorGet(errhp, 1, NULL, &errcode, (OraText*)errmsg, sizeof(errmsg), OCI_HTYPE_ERROR); \
fprintf(stderr, " %s\n", errmsg); \
} \
} while (0)
static void insert_xml(OCISvcCtx *svchp, OCIError *errhp, OCIType *xmltdo, xmlctx *xctx, const char *tag, const char *content);
static void select_xml(OCIEnv *envhp, OCISvcCtx *svchp, OCIError *errhp, OCIType *xmltdo, xmlctx *xctx, const char *tag_expected, const char *content_expected);
static const char *env(const char *name, const char *default_value)
{
const char *value = getenv(name);
return value ? value : default_value;
}
int main()
{
const char *username = env("ODPIC_TEST_MAIN_USER", "odpic");
const char *password = env("ODPIC_TEST_MAIN_PASSWORD", "welcome");
const char *database = env("ODPIC_TEST_CONNECT_STRING", "localhost/orclpdb");
OCIEnv *envhp;
OCIError *errhp;
OCISvcCtx *svchp;
OCIType *xmltdo;
const char *tag = "data";
size_t content_size = 64 * 1024 - 2;
char *content = malloc(content_size + 1);
memset(content, 'x', content_size);
content[content_size] = '\0';
chke(OCIEnvNlsCreate(&envhp, OCI_OBJECT, NULL, NULL, NULL, NULL, 0, NULL, CHARSET_ID_UTF8, CHARSET_ID_UTF8));
chke(OCIHandleAlloc(envhp, (void**)&errhp, OCI_HTYPE_ERROR, 0, NULL));
chk(OCILogon(envhp, errhp, &svchp, (OraText*)username, strlen(username), (OraText*)password, strlen(password), (OraText*)database, strlen(database)));
chk(OCITypeByName(envhp, errhp, svchp, (const OraText*)"SYS", 3, (const OraText*)"XMLTYPE", 7, NULL, 0, OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &xmltdo));
xmlctx *xctx = OCIXmlDbInitXmlCtx(envhp, svchp, errhp, NULL, 0);
insert_xml(svchp, errhp, xmltdo, xctx, tag, content);
select_xml(envhp, svchp, errhp, xmltdo, xctx, tag, content);
OCIXmlDbFreeXmlCtx(xctx);
chk(OCITransRollback(svchp, errhp, OCI_DEFAULT));
chk(OCILogoff(svchp, errhp));
}
static void insert_xml(OCISvcCtx *svchp, OCIError *errhp, OCIType *xmltdo, xmlctx *xctx, const char *tag, const char *content)
{
const char *sql = "insert into TestXML (IntCol, XMLCol) values (1, :xml)";
OCIStmt *stmtp;
OCIBind *bindp;
xmlerr err;
xmldocnode *doc;
xmlelemnode *top_elem;
int i;
doc = XmlCreateDocument(xctx, NULL, NULL, NULL, &err);
top_elem = XmlDomCreateElem(xctx, doc, (oratext*)tag);
XmlDomAppendChild(xctx, (xmlnode*)doc, (xmlnode*)top_elem);
for (i = 0; i < 10; i++) {
xmlelemnode *elem = XmlDomCreateElem(xctx, doc, (oratext*)tag);
xmltextnode *text = XmlDomCreateText(xctx, doc, (oratext*)content);
XmlDomAppendChild(xctx, (xmlnode*)top_elem, (xmlnode*)elem);
XmlDomAppendChild(xctx, (xmlnode*)elem, (xmlnode*)text);
}
chk(OCIStmtPrepare2(svchp, &stmtp, errhp, (OraText*)sql, strlen(sql), NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT));
chk(OCIBindByPos(stmtp, &bindp, errhp, 1, NULL, 0, SQLT_NTY, NULL, NULL, NULL, 0, NULL, OCI_DEFAULT));
chk(OCIBindObject(bindp, errhp, xmltdo, (void*)&doc, NULL, NULL, NULL));
chk(OCIStmtExecute(svchp, stmtp, errhp, 1, 0, NULL, NULL, OCI_DEFAULT));
chk(OCIStmtRelease(stmtp, errhp, NULL, 0, OCI_DEFAULT));
XmlFreeDocument(xctx, doc);
}
static void select_xml(OCIEnv *envhp, OCISvcCtx *svchp, OCIError *errhp, OCIType *xmltdo, xmlctx *xctx, const char *tag_expected, const char *content_expected)
{
const char *sql = "select XMLCol from TestXML where IntCol = 1";
OCIStmt *stmtp;
OCIDefine *defnp;
xmldocnode *doc = NULL;
xmlelemnode *elem;
xmltextnode *text;
const char *tag, *content;
int i;
chk(OCIStmtPrepare2(svchp, &stmtp, errhp, (OraText*)sql, strlen(sql), NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT));
chk(OCIDefineByPos(stmtp, &defnp, errhp, 1, NULL, 0, SQLT_NTY, NULL, NULL, NULL, OCI_DEFAULT));
chk(OCIDefineObject(defnp, errhp, xmltdo, (void*)&doc, NULL, NULL, NULL));
chk(OCIStmtExecute(svchp, stmtp, errhp, 1, 0, NULL, NULL, OCI_DEFAULT));
chk(OCIStmtRelease(stmtp, errhp, NULL, 0, OCI_DEFAULT));
elem = XmlDomGetDocElem(xctx, doc);
tag = (const char*)XmlDomGetTag(xctx, elem);
if (strcmp(tag, tag_expected) != 0) {
fprintf(stderr, "tag: expected '%s' but '%s'\n", tag_expected, tag);
}
for (i = 0; i < 10; i++) {
if (i == 0) {
elem = XmlDomGetFirstChild(xctx, elem);
} else {
elem = XmlDomGetNextSibling(xctx, elem);
}
tag = (const char*)XmlDomGetTag(xctx, elem);
if (strcmp(tag, tag_expected) != 0) {
fprintf(stderr, "tag: expected '%s' but '%s'\n", tag_expected, tag);
}
text = XmlDomGetFirstChild(xctx, elem);
content = (const char*)XmlDomGetCharData(xctx, text);
if (strcmp(content, content_expected) != 0) {
fprintf(stderr, "content: expected '%.100s...'(up to 100 bytes) but '%s'\n", content_expected, content);
}
}
chk(OCIObjectFree(envhp, errhp, doc, 0));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment