예제 #1
0
/*
 * Send an SQL query to the server
 */
static int db_oracle_submit_query(const db1_con_t* _h, const str* _s)
{
	OCIBind* bind[MAX_BIND_HANDLES];
	OCIDate odt[sizeof(bind)/sizeof(bind[0])];
	str tmps;
	sword status;
	int pass;
	ora_con_t* con = CON_ORA(_h);
	query_data_t* pqd = con->pqdata;
	size_t hc = pqd->_n + pqd->_nw;
	OCIStmt *stmthp;

	if (hc >= sizeof(bind)/sizeof(bind[0])) {
		LM_ERR("too many bound. Rebuild with MAX_BIND_HANDLES >= %u\n",
			(unsigned)hc);
		return -1;
	}
	
	if (!pqd->_rs) {
		/*
		 * This method is at ~25% faster as set OCI_COMMIT_ON_SUCCESS
		 * in StmtExecute
		 */
		tmps.len = snprintf(st_buf, sizeof(st_buf),
			"begin %.*s; commit write batch nowait; end;",
			_s->len, _s->s);
		if ((unsigned)tmps.len >= sizeof(st_buf))
			return sql_buf_small();
		tmps.s = st_buf;
		_s = &tmps;
	}

	pass = 1;
	if (!con->connected) {
		status = db_oracle_reconnect(con);
		if (status != OCI_SUCCESS) {
			LM_ERR("can't restore connection: %s\n", db_oracle_error(con, status));
			return -2;
		}
		LM_INFO("connection restored\n");
		--pass;
	}
repeat:
	stmthp = NULL;
	status = OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&stmthp,
		    OCI_HTYPE_STMT, 0, NULL);
	if (status != OCI_SUCCESS)
		goto ora_err;
	status = OCIStmtPrepare(stmthp, con->errhp, (text*)_s->s, _s->len,
		OCI_NTV_SYNTAX, OCI_DEFAULT);
	if (status != OCI_SUCCESS)
		goto ora_err;

	if (hc) {
		bmap_t bmap;
		size_t pos = 1;
		int i;

		memset(bind, 0, hc*sizeof(bind[0]));
		for (i = 0; i < pqd->_n; i++) {
			if (db_oracle_val2bind(&bmap, &pqd->_v[i], &odt[pos]) < 0)
				goto bind_err;
			status = OCIBindByPos(stmthp, &bind[pos], con->errhp,
				pos, bmap.addr, bmap.size, bmap.type,
				NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
			if (status != OCI_SUCCESS)
				goto ora_err;
			++pos;
		}
		for (i = 0; i < pqd->_nw; i++) {
			if (db_oracle_val2bind(&bmap, &pqd->_w[i], &odt[pos]) < 0) {
bind_err:
				OCIHandleFree(stmthp, OCI_HTYPE_STMT);
				LM_ERR("can't map values\n");
				return -3;
			}
			status = OCIBindByPos(stmthp, &bind[pos], con->errhp,
				pos, bmap.addr, bmap.size, bmap.type,
				NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
			if (status != OCI_SUCCESS)
				goto ora_err;
			++pos;
		}
	}

	// timelimited operation
	status = begin_timelimit(con, 0);
	if (status != OCI_SUCCESS) goto ora_err;
	do status = OCIStmtExecute(con->svchp, stmthp, con->errhp,
		!pqd->_rs, 0, NULL, NULL,
		pqd->_rs ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT);
	while (wait_timelimit(con, status));
	if (done_timelimit(con, status)) goto stop_exec;
	switch (status)	{
	case OCI_SUCCESS_WITH_INFO:
		LM_WARN("driver: %s\n", db_oracle_errorinfo(con));
		//PASS THRU
	case OCI_SUCCESS:
		if (pqd->_rs)
			*pqd->_rs = stmthp;
		else
			OCIHandleFree(stmthp, OCI_HTYPE_STMT);
		return 0;
	default:
	    pass = -pass;
	    break;
	}

ora_err:
	LM_ERR("driver: %s\n", db_oracle_error(con, status));
stop_exec:
	if (stmthp)
		OCIHandleFree(stmthp, OCI_HTYPE_STMT);
	if (pass == -1 && !con->connected) {
		/* Attemtp to reconnect */
		if (db_oracle_reconnect(con) == OCI_SUCCESS) {
			LM_NOTICE("attempt repeat after reconnect\n");
			pass = 0;
			goto repeat;
		}
		LM_ERR("connection loss\n");
	}
	return -4;
}
예제 #2
0
/*
 * Create a new connection structure,
 * open the Oracle connection and set reference count to 1
 */
ora_con_t* db_oracle_new_connection(const struct db_id* id)
{
	ora_con_t* con;
	char buf[512];
	size_t uri_len;
	sword status;

	if (!id || !id->username || !*id->username || !id->password ||
		!*id->password || !id->database || !*id->database)
	{
bad_param:
		LM_ERR("invalid parameter value\n");
		return NULL;
	}


	if (!id->host || !*id->host) {
		if (id->port) goto bad_param;
		uri_len = snprintf(buf, sizeof(buf), "%s", id->database);
	} else if (id->port) {
		uri_len = snprintf(buf, sizeof(buf), "%s:%u/%s",
				id->host, id->port, id->database);
	} else {
		uri_len = snprintf(buf, sizeof(buf), "%s/%s",
				id->host, id->database);
	}
	if (uri_len >= sizeof(buf)) goto bad_param;
	LM_DBG("opening connection: oracle://xxxx:xxxx@%s\n", buf);

	con = (ora_con_t*)pkg_malloc(sizeof(*con) + uri_len+1);
	if (!con) {
		LM_ERR("no private memory left\n");
		return NULL;
	}

	memset(con, 0, sizeof(*con));
	con->hdr.ref = 1;
	con->hdr.id = (struct db_id*)id;	/* set here - freed on error */
	con->uri_len = uri_len;
	memcpy(con->uri, buf, uri_len+1);

	if (   OCIEnvCreate(&con->envhp,
			OCI_DEFAULT | OCI_NEW_LENGTH_SEMANTICS,
            		NULL, NULL, NULL, NULL, 0, NULL) != OCI_SUCCESS
	    || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->errhp,
		    OCI_HTYPE_ERROR, 0, NULL) != OCI_SUCCESS
	    || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->srvhp,
		    OCI_HTYPE_SERVER, 0, NULL) != OCI_SUCCESS
	    || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->svchp,
		    OCI_HTYPE_SVCCTX, 0, NULL) != OCI_SUCCESS
	    || OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&con->authp,
        	    OCI_HTYPE_SESSION, 0, NULL) != OCI_SUCCESS)
	{

		LM_ERR("no oracle memory left\n");
		db_oracle_free_connection(con);
		return NULL;
	}

	status = OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, con->srvhp, 0,
			OCI_ATTR_SERVER, con->errhp);
	if (status != OCI_SUCCESS) goto connect_err;
	status = OCIAttrSet(con->authp, OCI_HTYPE_SESSION,
                 id->username, (ub4)strlen(id->username),
                 OCI_ATTR_USERNAME, con->errhp);
	if (status != OCI_SUCCESS) goto connect_err;
	status = OCIAttrSet(con->authp, OCI_HTYPE_SESSION,
                 id->password, (ub4)strlen(id->password),
                 OCI_ATTR_PASSWORD, con->errhp);
	if (status != OCI_SUCCESS) goto connect_err;
	status = OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, con->authp, 0,
                   OCI_ATTR_SESSION, con->errhp);
	if (status != OCI_SUCCESS) goto connect_err;
	status = db_oracle_reconnect(con);
	if (status != OCI_SUCCESS) {
connect_err:
		if (   (status != OCI_ERROR && status != OCI_SUCCESS_WITH_INFO)
		    || OCIErrorGet(con->errhp, 1, NULL, &status, (OraText*)buf,
			    sizeof(buf), OCI_HTYPE_ERROR) != OCI_SUCCESS)
		{
			LM_ERR("internal driver error\n");
		} else {
			LM_ERR("driver: %s\n", buf);
		}
drop_connection:
		db_oracle_free_connection(con);
		return NULL;
	}

	// timelimited operation
	status = begin_timelimit(con, 0);
	if (status != OCI_SUCCESS) goto connect_err;
	do status = OCIServerVersion(con->svchp, con->errhp, (OraText*)buf,
		(ub4)sizeof(buf), OCI_HTYPE_SVCCTX);
	while (wait_timelimit(con, status));
	if (done_timelimit(con, status)) goto drop_connection;
	if (status != OCI_SUCCESS) goto connect_err;
	LM_INFO("server version is %s\n", buf);
	return con;
}