SQLRETURN config_dbc()

in driver/connect.c [1234:1655]


SQLRETURN config_dbc(esodbc_dbc_st *dbc, esodbc_dsn_attrs_st *attrs)
{
	const static wstr_st http_prefix = WSTR_INIT("http://");
	const static wstr_st https_prefix = WSTR_INIT("https://");
	wstr_st prefix;
	int cnt, ipv6, n;
	SQLBIGINT secure, timeout, max_body_size, max_fetch_size, varchar_limit;
	SQLWCHAR buff_url[ESODBC_MAX_URL_LEN];
	wstr_st url = (wstr_st) {
		buff_url, /*will be init'ed later*/0
	};

	/*
	 * setup logging
	 */
	if (! config_dbc_logging(dbc, attrs)) {
		/* attempt global logging the error */
		ERRH(dbc, "failed to setup DBC logging");
		goto err;
	}

	if (attrs->cloud_id.cnt && (! decode_cloud_id(dbc, attrs))) {
		goto err;
	} else if (http_prefix.cnt <= attrs->server.cnt) {
		/* make sure that user didn't input a HTTP URL (common mistake):
		 * the error libcurl returns is not particularly descriptive */
		do {
			prefix = attrs->server;
			prefix.cnt = http_prefix.cnt;
			if (! EQ_CASE_WSTR(&prefix, &http_prefix)) {
				if (attrs->server.cnt < https_prefix.cnt) {
					break;
				}
				prefix.cnt = https_prefix.cnt;
				if (! EQ_CASE_WSTR(&prefix, &https_prefix)) {
					break;
				}
			}
			ERRH(dbc, "hostname `" LWPDL "` can't be a HTTP(S) URL.",
				LWSTR(&attrs->server));
			SET_HDIAG(dbc, SQL_STATE_HY000, "The Hostname can't be a HTTP(S) "
				"URL: remove the 'http(s)://' prefix (and port suffix, "
				"if present).", 0);
			goto err;
		} while (0);
	}

	if (str2bigint(&attrs->secure, /*wide?*/TRUE, &secure, /*stri*/TRUE) < 0) {
		ERRH(dbc, "failed to read secure param `" LWPDL "`.",
			LWSTR(&attrs->secure));
		SET_HDIAG(dbc, SQL_STATE_HY000, "security setting number "
			"conversion failure", 0);
		goto err;
	}
	if (secure < ESODBC_SEC_NONE || ESODBC_SEC_MAX <= secure) {
		ERRH(dbc, "invalid secure param `" LWPDL "` (not within %d - %d).",
			LWSTR(&attrs->secure), ESODBC_SEC_NONE, ESODBC_SEC_MAX - 1);
		SET_HDIAG(dbc, SQL_STATE_HY000, "invalid security setting", 0);
		goto err;
	} else {
		dbc->secure = (int)secure;
		INFOH(dbc, "connection security level: %ld.", dbc->secure);
	}

	if (secure) {
		if (! wstr_to_utf8(&attrs->ca_path, &dbc->ca_path)) {
			ERRH(dbc, "failed to convert CA path `" LWPDL "` to UTF8.",
				LWSTR(&attrs->ca_path));
			SET_HDIAG(dbc, SQL_STATE_HY000, "reading the CA file path "
				"failed", 0);
			goto err;
		}
		INFOH(dbc, "CA path: `%s`.", dbc->ca_path.str);
	}

	/*
	 * SQL close and query URL of the cluster
	 */
	/* Note: libcurl won't check hostname validity, it'll just try to resolve
	 * whatever it receives, if it can parse the URL */
	ipv6 = wcsnstr(attrs->server.str, attrs->server.cnt, L':') != NULL;
	cnt = swprintf(url.str, sizeof(buff_url)/sizeof(*buff_url),
			L"http" WPFCP_DESC "://"
			WPFCP_DESC WPFWP_LDESC WPFCP_DESC ":" WPFWP_LDESC
			ELASTIC_SQL_PATH /*+*/ ELASTIC_SQL_CLOSE_SUBPATH,
			secure ? "s" : "",
			ipv6 ? "[" : "", LWSTR(&attrs->server), ipv6 ? "]" : "",
			LWSTR(&attrs->port));
	if (cnt <= 0) {
		ERRNH(dbc, "failed to print SQL URL out of server: `" LWPDL "`, "
			"port: `" LWPDL "`.", LWSTR(&attrs->server), LWSTR(&attrs->port));
		SET_HDIAG(dbc, SQL_STATE_HY000, "printing server's SQL URL failed", 0);
		goto err;
	} else {
		url.cnt = (size_t)cnt;
	}
	if (! wstr_to_utf8(&url, &dbc->close_url)) {
		ERRH(dbc, "failed to convert URL `" LWPDL "` to UTF8.", LWSTR(&url));
		SET_HDIAG(dbc, SQL_STATE_HY000, "server SQL URL's UTF8 conversion "
			"failed", 0);
		goto err;
	}
	INFOH(dbc, "connection SQL cusor closing URL: `%s`.", dbc->close_url.str);

	/* shorten the length of string in buffer, before dup'ing; it needs to be
	 * dup'ed since libcurl needs the 0 terminator */
	url.cnt -= sizeof(ELASTIC_SQL_CLOSE_SUBPATH) - /*\0*/1;
	if (! wstr_to_utf8(&url, &dbc->url)) {
		ERRH(dbc, "failed to convert URL `" LWPDL "` to UTF8.", LWSTR(&url));
		SET_HDIAG(dbc, SQL_STATE_HY000, "server SQL URL's UTF8 conversion "
			"failed", 0);
		goto err;
	}
	INFOH(dbc, "connection SQL query URL: `%s`.", dbc->url.str);

	/*
	 * Root URL of the cluster
	 */
	cnt = swprintf(url.str, sizeof(buff_url)/sizeof(*buff_url),
			L"http" WPFCP_DESC "://"
			WPFCP_DESC WPFWP_LDESC WPFCP_DESC ":" WPFWP_LDESC "/",
			secure ? "s" : "",
			ipv6 ? "[" : "", LWSTR(&attrs->server), ipv6 ? "]" : "",
			LWSTR(&attrs->port));
	if (cnt <= 0) {
		ERRNH(dbc, "failed to print root URL out of server: `" LWPDL "`,"
			" port: `" LWPDL "`.", LWSTR(&attrs->server), LWSTR(&attrs->port));
		SET_HDIAG(dbc, SQL_STATE_HY000, "printing server's URL failed", 0);
		goto err;
	} else {
		url.cnt = (size_t)cnt;
	}
	if (! wstr_to_utf8(&url, &dbc->root_url)) {
		ERRH(dbc, "failed to convert URL `" LWPDL "` to UTF8.", LWSTR(&url));
		SET_HDIAG(dbc, SQL_STATE_HY000, "server root URL's UTF8 conversion "
			"failed", 0);
		goto err;
	}
	INFOH(dbc, "connection root URL: `%s`.", dbc->root_url.str);

	/*
	 * credentials
	 */
	if (attrs->uid.cnt) {
		if (! wstr_to_utf8(&attrs->uid, &dbc->uid)) {
			ERRH(dbc, "failed to convert username [%zu] `" LWPDL "` to UTF8.",
				attrs->uid.cnt, LWSTR(&attrs->uid));
			SET_HDIAG(dbc, SQL_STATE_HY000, "username UTF8 conversion "
				"failed", 0);
			goto err;
		}
		INFOH(dbc, "connection UID: `%s`.", dbc->uid.str);
		if (attrs->pwd.cnt) {
			if (! wstr_to_utf8(&attrs->pwd, &dbc->pwd)) {
				ERRH(dbc, "failed to convert password [%zu] `%s` to "
					"UTF8.", attrs->pwd.cnt, ESODBC_PWD_VAL_SUBST);
				SET_HDIAG(dbc, SQL_STATE_HY000, "password UTF8 "
					"conversion failed", 0);
				goto err;
			}
			/* indicates the presence of a non-empty password */
			INFOH(dbc, "connection PWD: " ESODBC_PWD_VAL_SUBST ".");
		}
	} else if (attrs->api_key.cnt) {
		if (! wstr_to_utf8(&attrs->api_key, &dbc->api_key)) {
			ERRH(dbc, "failed to convert API key [%zu] `" LWPDL "` to UTF8.",
				attrs->api_key.cnt, LWSTR(&attrs->api_key));
			SET_HDIAG(dbc, SQL_STATE_HY000, "API key UTF8 conversion failed",
				0);
			goto err;
		}
	}

	/* "follow location" param for liburl */
	dbc->follow = wstr2bool(&attrs->follow);
	INFOH(dbc, "follow: %s.", dbc->follow ? "true" : "false");

	/*
	 * request timeout for liburl: negative reset to 0
	 */
	if (str2bigint(&attrs->timeout, /*wide?*/TRUE, &timeout,
			/*strict*/TRUE) < 0) {
		ERRH(dbc, "failed to convert `" LWPDL "` [%zu] to big int.",
			LWSTR(&attrs->timeout), attrs->timeout.cnt);
		SET_HDIAG(dbc, SQL_STATE_HY000, "timeout setting number "
			"conversion failure", 0);
		goto err;
	}
	if (ULONG_MAX <= timeout || timeout < 0) {
		WARNH(dbc, "invalid timeout value (%lld), normalized to 0.", timeout);
		timeout = 0;
	}
	dbc->timeout = (SQLUINTEGER)timeout;
	INFOH(dbc, "timeout: %lu.", dbc->timeout);

	/*
	 * proxy settings
	 */
	if (wstr2bool(&attrs->proxy_enabled)) {
		ipv6 = wcsnstr(attrs->proxy_host.str, attrs->proxy_host.cnt, L':') !=
			NULL;
		cnt = swprintf(url.str, sizeof(buff_url)/sizeof(*buff_url),
				L"" WPFWP_LDESC "://" WPFCP_DESC WPFWP_LDESC WPFCP_DESC,
				LWSTR(&attrs->proxy_type),
				ipv6 ? "[" : "", LWSTR(&attrs->proxy_host), ipv6 ? "]" : "");
		if (cnt > 0 && attrs->proxy_port.cnt) {
			n = swprintf(url.str + cnt,
					sizeof(buff_url)/sizeof(*buff_url) - cnt,
					L":" WPFWP_LDESC, LWSTR(&attrs->proxy_port));
		} else {
			n = 0;
		}
		if (cnt <= 0 || n < 0) {
			ERRNH(dbc, "failed to print proxy URL out of type: `" LWPDL "`, "
				"host: `" LWPDL "` and port: `" LWPDL "`.",
				LWSTR(&attrs->proxy_type), LWSTR(&attrs->proxy_host),
				LWSTR(&attrs->proxy_port));
			SET_HDIAG(dbc, SQL_STATE_HY000, "printing proxy URL failed", 0);
			goto err;
		} else {
			url.cnt = cnt + n;
		}
		if (! wstr_to_utf8(&url, &dbc->proxy_url)) {
			ERRH(dbc, "failed to convert URL `" LWPDL "` to UTF8.",
				LWSTR(&url));
			SET_HDIAG(dbc, SQL_STATE_HY000, "proxy URL's UTF8 conversion "
				"failed", 0);
			goto err;
		}
		INFOH(dbc, "proxy URL: `%s`.", dbc->proxy_url.str);

		if (wstr2bool(&attrs->proxy_auth_enabled)) {
			if (attrs->proxy_auth_uid.cnt) {
				if (! wstr_to_utf8(&attrs->proxy_auth_uid, &dbc->proxy_uid)) {
					ERRH(dbc, "failed to convert proxy user ID `" LWPDL "` to"
						" UTF8.", LWSTR(&attrs->proxy_auth_uid));
					SET_HDIAG(dbc, SQL_STATE_HY000, "proxy UID's UTF8 "
						"conversion failed", 0);
					goto err;
				}
				INFOH(dbc, "proxy UID: `%s`.", dbc->proxy_uid.str);

				if (attrs->proxy_auth_pwd.cnt) {
					if (! wstr_to_utf8(&attrs->proxy_auth_pwd,
							&dbc->proxy_pwd)) {
						ERRH(dbc, "failed to convert proxy password [%zu] `%s`"
							" to UTF8", attrs->proxy_auth_pwd.cnt,
							ESODBC_PWD_VAL_SUBST);
						SET_HDIAG(dbc, SQL_STATE_HY000, "proxy password's "
							"UTF8 conversion failed", 0);
						goto err;
					}
					/* indicates the presence of a non-empty password */
					INFOH(dbc, "proxy PWD: " ESODBC_PWD_VAL_SUBST ".");
				}
			}
		} else {
			INFOH(dbc, "proxy authentication disabled.");
		}
	} else {
		INFOH(dbc, "proxy disabled.");
	}

	/*
	 * set max body size
	 */
	if (str2bigint(&attrs->max_body_size, /*wide?*/TRUE, &max_body_size,
			/*strict*/TRUE) < 0) {
		ERRH(dbc, "failed to convert max body size [%zu] `" LWPDL "`.",
			attrs->max_body_size.cnt, LWSTR(&attrs->max_body_size));
		SET_HDIAG(dbc, SQL_STATE_HY000, "max body size setting number "
			"conversion failure", 0);
		goto err;
	}
	if ((SIZE_MAX / (1024 * 1024)) <= max_body_size || max_body_size < 0) {
		ERRH(dbc, "invalid '%s' setting value (%lld).",
			ESODBC_DSN_MAX_BODY_SIZE_MB, max_body_size);
		SET_HDIAG(dbc, SQL_STATE_HY000, "invalid max body size setting", 0);
		goto err;
	} else {
		dbc->amax = (size_t)max_body_size * 1024 * 1024;
		if (! dbc->amax) {
			WARNH(dbc, "no reply body limit set.");
		}
	}
	INFOH(dbc, "max body size: %zu.", dbc->amax);

	/*
	 * set max fetch size
	 */
	if (str2bigint(&attrs->max_fetch_size, /*wide?*/TRUE, &max_fetch_size,
			/*strict*/TRUE) < 0) {
		ERRH(dbc, "failed to convert max fetch size [%zu] `" LWPDL "`.",
			attrs->max_fetch_size.cnt, LWSTR(&attrs->max_fetch_size));
		SET_HDIAG(dbc, SQL_STATE_HY000, "max fetch size setting number "
			"conversion failure", 0);
		goto err;
	}
	if (SIZE_MAX <= max_fetch_size || max_fetch_size < 0) {
		ERRH(dbc, "invalid '%s' setting value (%lld).",
			ESODBC_DSN_MAX_FETCH_SIZE, max_fetch_size);
		SET_HDIAG(dbc, SQL_STATE_HY000, "invalid max fetch size setting", 0);
		goto err;
	} else {
		dbc->fetch.max = (size_t)max_fetch_size;
	}
	/* set the string representation of fetch_size, once for all STMTs */
	if (dbc->fetch.max) {
		dbc->fetch.slen = (char)attrs->max_fetch_size.cnt;
		dbc->fetch.str = malloc(dbc->fetch.slen + /*\0*/1);
		if (! dbc->fetch.str) {
			ERRNH(dbc, "failed to alloc %cB.", dbc->fetch.slen);
			RET_HDIAGS(dbc, SQL_STATE_HY001);
		}
		dbc->fetch.str[dbc->fetch.slen] = 0;
		ascii_w2c(attrs->max_fetch_size.str, dbc->fetch.str, dbc->fetch.slen);
	}
	INFOH(dbc, "fetch_size: %s.", dbc->fetch.str ? dbc->fetch.str : "none" );


	/*
	 * set the REST body format: JSON/CBOR
	 */
	if (EQ_CASE_WSTR(&attrs->packing, &MK_WSTR(ESODBC_DSN_PACK_JSON))) {
		dbc->pack_json = TRUE;
	} else if (EQ_CASE_WSTR(&attrs->packing, &MK_WSTR(ESODBC_DSN_PACK_CBOR))) {
		dbc->pack_json = FALSE;
	} else {
		ERRH(dbc, "unknown packing encoding '" LWPDL "'.",
			LWSTR(&attrs->packing));
		SET_HDIAG(dbc, SQL_STATE_HY000, "invalid packing encoding setting", 0);
		goto err;
	}
	INFOH(dbc, "pack JSON: %s.", dbc->pack_json ? "true" : "false");

	/*
	 * set the compression option: auto/on/off
	 */
	if (EQ_CASE_WSTR(&attrs->compression, &MK_WSTR(ESODBC_DSN_CMPSS_AUTO))) {
		dbc->compression = ESODBC_CMPSS_AUTO;
	} else {
		dbc->compression = wstr2bool(&attrs->compression) ?
			ESODBC_CMPSS_ON : ESODBC_CMPSS_OFF;
	}
	INFOH(dbc, "compression: %d (" LWPDL ").", dbc->compression,
		LWSTR(&attrs->compression));

	/* "apply TZ" param for time conversions */
	dbc->apply_tz = wstr2bool(&attrs->apply_tz);
	INFOH(dbc, "apply TZ: %s.", dbc->apply_tz ? "true" : "false");
	/* early execution */
	dbc->early_exec = wstr2bool(&attrs->early_exec);
	INFOH(dbc, "early execution: %s.", dbc->early_exec ? "true" : "false");
	/* default current catalog */
	if (attrs->catalog.cnt &&
		(! SQL_SUCCEEDED(set_current_catalog(dbc, &attrs->catalog)))) {
		goto err;
	}

	/* how to print the floats? */
	assert(1 <= attrs->sci_floats.cnt); /* default should apply */
	if ((char)attrs->sci_floats.str[0] == ESODBC_DSN_FLTS_DEF[0]) {
		dbc->sci_floats = ESODBC_FLTS_DEFAULT;
	} else if ((char)attrs->sci_floats.str[0] == ESODBC_DSN_FLTS_SCI[0]) {
		dbc->sci_floats = ESODBC_FLTS_SCIENTIFIC;
	} else if ((char)attrs->sci_floats.str[0] == ESODBC_DSN_FLTS_AUTO[0]) {
		dbc->sci_floats = ESODBC_FLTS_AUTO;
	} else {
		ERRH(dbc, "unknown floats representation '" LWPDL "'.",
			LWSTR(&attrs->sci_floats));
		SET_HDIAG(dbc, SQL_STATE_HY000,
			"invalid floats representation setting", 0);
		goto err;
	}

	/* "multifield leniency" param */
	dbc->mfield_lenient = wstr2bool(&attrs->mfield_lenient);
	INFOH(dbc, "multifield lenient: %s.",
		dbc->mfield_lenient ? "true" : "false");
	/* "index include frozen" param */
	dbc->idx_inc_frozen = wstr2bool(&attrs->idx_inc_frozen);
	INFOH(dbc, "index include frozen: %s.",
		dbc->idx_inc_frozen ? "true" : "false");
	/* auto escape pattern value argument */
	dbc->auto_esc_pva = wstr2bool(&attrs->auto_esc_pva);
	INFOH(dbc, "auto escape PVA: %s.", dbc->auto_esc_pva ? "true" : "false");
	/* varchar limit */
	if (str2bigint(&attrs->varchar_limit, /*wide?*/TRUE, &varchar_limit,
			/*strict*/TRUE) < 0) {
		ERRH(dbc, "failed to convert varchar limit [%zu] `" LWPDL "`.",
			attrs->varchar_limit.cnt, LWSTR(&attrs->varchar_limit));
		SET_HDIAG(dbc, SQL_STATE_HY000, "varchar limit value conversion "
			"failure", 0);
		goto err;
	} else if (ESODBC_MAX_KEYWORD_PRECISION < varchar_limit ||
		varchar_limit < 0) {
		ERRH(dbc, "varchar limit (`" LWPDL "`) outside the allowed range "
			"[%d, %d].", LWSTR(&attrs->varchar_limit), 0,
			ESODBC_MAX_KEYWORD_PRECISION);
		SET_HDIAG(dbc, SQL_STATE_HY000, "invalid varchar limit setting", 0);
		goto err;
	} else {
		dbc->varchar_limit = (SQLUINTEGER)varchar_limit;
		/* duplicate w-char setting */
		if (! (dbc->varchar_limit_str.str = calloc(attrs->varchar_limit.cnt +
						/*\0*/1, sizeof(SQLWCHAR)))) {
			ERRNH(dbc, "OOM: %zu w-chars.", attrs->varchar_limit.cnt + 1);
			SET_HDIAG(dbc, SQL_STATE_HY001, "Memory allocation error", 0);
			goto err;
		}
		wmemcpy(dbc->varchar_limit_str.str, attrs->varchar_limit.str,
			attrs->varchar_limit.cnt);
		dbc->varchar_limit_str.cnt = attrs->varchar_limit.cnt;
		INFOH(dbc, "varchar limit: %lu.", dbc->varchar_limit);
	}

	return SQL_SUCCESS;
err:
	/* release allocated resources before the failure; not the diag, tho */
	cleanup_dbc(dbc);
	RET_STATE(dbc->hdr.diag.state);
}