SQLRETURN SQL_API RsCatalog::RS_SQLTables()

in src/odbc/rsodbc/rscatalog.cpp [489:720]


SQLRETURN  SQL_API RsCatalog::RS_SQLTables(SQLHSTMT phstmt,
                               SQLCHAR *pCatalogName, 
                               SQLSMALLINT cbCatalogName,
                               SQLCHAR *pSchemaName, 
                               SQLSMALLINT cbSchemaName,
                               SQLCHAR *pTableName, 
                               SQLSMALLINT cbTableName,
                               SQLCHAR *pTableType, 
                               SQLSMALLINT cbTableType)
{
    SQLRETURN rc = SQL_SUCCESS;
    RS_STMT_INFO *pStmt = (RS_STMT_INFO *)phstmt;

    // Clear error list
    pStmt->pErrorList = clearErrorList(pStmt->pErrorList);

	if(showDiscoveryVersion(pStmt) >= MIN_SHOW_DISCOVERY_VERSION){
		if (isNullOrEmptyString(pSchemaName) && isNullOrEmptyString(pTableName) && isSqlAllCatalogs(pCatalogName, cbCatalogName))
		{
			SQLHSTMT internalStmt;
			rc = RS_CONN_INFO::RS_SQLAllocStmt(pStmt->phdbc, &internalStmt);
			if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
				RS_LOG_ERROR("RS_CONN_INFO::RS_SQLAllocStmt", "Fail to allocate new statement for internal use");
				addError(&pStmt->pErrorList, "HY000", "RS_CONN_INFO::RS_SQLAllocStmt, Fail to allocate new statement for internal use", 0, NULL);
				return rc;
			}

			//  Special SQLTables call : get catalog list
			std::vector<std::string> intermediateRS;
			rc = RsMetadataServerAPIHelper::sqlCatalogsServerAPI(internalStmt, intermediateRS, isSingleDatabaseMetaData(pStmt));
			if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO){
				RS_LOG_ERROR("RsMetadataServerAPIHelper.sqlCatalogsServerAPI", "Fail get intermediate result set for SQLTables");
				addError(&pStmt->pErrorList,"HY000", "RsMetadataServerAPIHelper.sqlCatalogsServerAPI fail", 0, NULL);
				return rc;
			}

			rc = RS_STMT_INFO::RS_SQLFreeStmt(internalStmt,SQL_DROP, TRUE);
			if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
				RS_LOG_ERROR("RS_STMT_INFO::RS_SQLFreeStmt", "Fail to free statement for internal use");
				addError(&pStmt->pErrorList, "HY000", "RS_STMT_INFO::RS_SQLFreeStmt, Fail to free statement for internal use", 0, NULL);
				return rc;
			}

			rc = RsMetadataAPIPostProcessing::sqlCatalogsPostProcessing(phstmt, intermediateRS);
			if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO){
				RS_LOG_ERROR("RsMetadataAPIPostProcessing.sqlCatalogsPostProcessing", "Fail call post-processing for SQLTables");
				addError(&pStmt->pErrorList,"HY000", "RsMetadataAPIPostProcessing.sqlCatalogsPostProcessing fail", 0, NULL);
				return rc;
			}
		}
		else 
		if(isNullOrEmptyString(pCatalogName) && isNullOrEmptyString(pTableName) && isSqlAllSchemas(pSchemaName, cbSchemaName))
		{
			SQLHSTMT internalStmt;
			rc = RS_CONN_INFO::RS_SQLAllocStmt(pStmt->phdbc, &internalStmt);
			if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
				RS_LOG_ERROR("RS_CONN_INFO::RS_SQLAllocStmt", "Fail to allocate new statement for internal use");
				addError(&pStmt->pErrorList, "HY000", "RS_CONN_INFO::RS_SQLAllocStmt, Fail to allocate new statement for internal use", 0, NULL);
				return rc;
			}

			//  Special SQLTables call : get schema list
			std::vector<SHOWSCHEMASResult> intermediateRS;
			rc = RsMetadataServerAPIHelper::sqlSchemasServerAPI(internalStmt, intermediateRS, isSingleDatabaseMetaData(pStmt));
			if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO){
				RS_LOG_ERROR("RsMetadataServerAPIHelper.sqlSchemasServerAPI", "Fail get intermediate result set for SQLTables");
				addError(&pStmt->pErrorList,"HY000", "RsMetadataServerAPIHelper.sqlSchemasServerAPI fail", 0, NULL);
				return rc;
			}

			rc = RS_STMT_INFO::RS_SQLFreeStmt(internalStmt,SQL_DROP, TRUE);
			if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
				RS_LOG_ERROR("RS_STMT_INFO::RS_SQLFreeStmt", "Fail to free statement for internal use");
				addError(&pStmt->pErrorList, "HY000", "RS_STMT_INFO::RS_SQLFreeStmt, Fail to free statement for internal use", 0, NULL);
				return rc;
			}

			rc = RsMetadataAPIPostProcessing::sqlSchemasPostProcessing(phstmt, intermediateRS);
			if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO){
				RS_LOG_ERROR("RsMetadataAPIPostProcessing.sqlSchemasPostProcessing", "Fail call post-processing for SQLTables");
				addError(&pStmt->pErrorList,"HY000", "RsMetadataAPIPostProcessing.sqlSchemasPostProcessing fail", 0, NULL);
				return rc;
			}

		}
		else
		if(isNullOrEmptyString(pCatalogName) && isNullOrEmptyString(pSchemaName) && isNullOrEmptyString(pTableName) && isSqlAllTableTypes(pTableType, cbTableType))
		{
			// Special SQLTables call : get table type list
			rc = RsMetadataAPIPostProcessing::sqlTableTypesPostProcessing(phstmt);
			if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO){
				RS_LOG_ERROR("RsMetadataAPIPostProcessing.sqlTableTypesPostProcessing", "Fail call post-processing for SQLTables");
				addError(&pStmt->pErrorList,"HY000", "RsMetadataAPIPostProcessing.sqlTableTypesPostProcessing fail", 0, NULL);
				return rc;
			}
		}
		else{
			// Normal SQLTables call

			std::string catalogName = (isNullOrEmptyString(pCatalogName)) ? "" : char2String(pCatalogName);

			std::string schemaName = (isNullOrEmptyString(pSchemaName)) ? "" : char2String(pSchemaName);

			std::string tableName = (isNullOrEmptyString(pTableName)) ? "" : char2String(pTableName);

			// Return Empty ResultSet if catalog or schemaPattern or tableNamePattern is empty string
			//bool retEmpty = isEmptyString(pCatalogName) || isEmptyString(pSchemaName) || isEmptyString(pTableName); // comment this out since the Driver will still accept empty string for now
			bool retEmpty = false; // Map empty string to wildcard internally but will block them in the near future

			SQLHSTMT internalStmt;
			rc = RS_CONN_INFO::RS_SQLAllocStmt(pStmt->phdbc, &internalStmt);
			if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
				RS_LOG_ERROR("RS_CONN_INFO::RS_SQLAllocStmt", "Fail to allocate new statement for internal use");
				addError(&pStmt->pErrorList, "HY000", "RS_CONN_INFO::RS_SQLAllocStmt, Fail to allocate new statement for internal use", 0, NULL);
				return rc;
			}

			std::vector<SHOWTABLESResult> intermediateRS;
			rc = RsMetadataServerAPIHelper::sqlTablesServerAPI(internalStmt, catalogName, schemaName, tableName, retEmpty, intermediateRS, isSingleDatabaseMetaData(pStmt));
			if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO){
				RS_LOG_ERROR("RsMetadataServerAPIHelper.sqlTablesServerAPI", "Fail get intermediate result set for SQLTables");
				addError(&pStmt->pErrorList,"HY000", "RsMetadataServerAPIHelper.sqlTablesServerAPI fail", 0, NULL);
				return rc;
			}

			rc = RS_STMT_INFO::RS_SQLFreeStmt(internalStmt,SQL_DROP, TRUE);
			if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
				RS_LOG_ERROR("RS_STMT_INFO::RS_SQLFreeStmt", "Fail to free statement for internal use");
				addError(&pStmt->pErrorList, "HY000", "RS_STMT_INFO::RS_SQLFreeStmt, Fail to free statement for internal use", 0, NULL);
				return rc;
			}

			std::string table_type = (!pTableType) ? "" : char2String(pTableType);

			rc = RsMetadataAPIPostProcessing::sqlTablesPostProcessing(phstmt, table_type, retEmpty, intermediateRS);
			if(rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO){
				RS_LOG_ERROR("RsMetadataAPIPostProcessing.sqlTablesPostProcessing", "Fail call post-processing for SQLTables");
				addError(&pStmt->pErrorList,"HY000", "RsMetadataAPIPostProcessing.sqlTablesPostProcessing fail", 0, NULL);
				return rc;
			}
		}
	}
	else{
		// Old code path is retained for supporting legacy cluster version which doesn't not support Server API SHOW command
		char szCatalogQuery[MAX_CATALOG_QUERY_LEN];
		if (isNullOrEmptyString(pSchemaName) && isNullOrEmptyString(pTableName) && isSqlAllCatalogs(pCatalogName, cbCatalogName))
		{
			if (isSingleDatabaseMetaData(pStmt))
				rs_strncpy(szCatalogQuery, SQLTABLES_ALL_CATALOG_QUERY, sizeof(szCatalogQuery));
			else
				rs_strncpy(szCatalogQuery, SQLTABLES_ALL_CATALOG_QUERY_DATASHARE, sizeof(szCatalogQuery));
		}
		else 
		if(isNullOrEmptyString(pCatalogName) && isNullOrEmptyString(pTableName) && isSqlAllSchemas(pSchemaName, cbSchemaName))
		{
			if (isSingleDatabaseMetaData(pStmt))
				rs_strncpy(szCatalogQuery, SQLTABLES_ALL_SCHEMAS_QUERY, sizeof(szCatalogQuery));
			else
				rs_strncpy(szCatalogQuery, SQLTABLES_ALL_SCHEMAS_QUERY_DATASHARE, sizeof(szCatalogQuery));
		}
		else
		if(isNullOrEmptyString(pCatalogName) && isNullOrEmptyString(pSchemaName) && isNullOrEmptyString(pTableName) && isSqlAllTableTypes(pTableType, cbTableType))
		{
			rs_strncpy(szCatalogQuery, SQLTABLES_ALL_TABLE_TYPES_QUERY, sizeof(szCatalogQuery));
		}
		else
		{
			int schemaPatternType = getExtSchemaPatternMatch(pStmt, pSchemaName, cbSchemaName);

			if (schemaPatternType == LOCAL_SCHEMA_QUERY)
			{
				// Join on pg_catalog
				buildLocalSchemaTablesQuery(szCatalogQuery, pStmt,
					pCatalogName,
					cbCatalogName,
					pSchemaName,
					cbSchemaName,
					pTableName,
					cbTableName,
					pTableType,
					cbTableType);
			}
			else if (schemaPatternType == NO_SCHEMA_UNIVERSAL_QUERY) 
			{
				if (isSingleDatabaseMetaData(pStmt))
				{
					// svv_tables
					buildUniversalSchemaTablesQuery(szCatalogQuery, pStmt,
													pCatalogName,
													cbCatalogName,
													pSchemaName,
													cbSchemaName,
													pTableName,
													cbTableName,
													pTableType,
													cbTableType);
				}
				else {
					// svv_all_tables
					buildUniversalAllSchemaTablesQuery(szCatalogQuery, pStmt,
						pCatalogName,
						cbCatalogName,
						pSchemaName,
						cbSchemaName,
						pTableName,
						cbTableName,
						pTableType,
						cbTableType);
				}
			}
			else if (schemaPatternType == EXTERNAL_SCHEMA_QUERY) {
				// svv_external_tables
				buildExternalSchemaTablesQuery(szCatalogQuery, pStmt,
					pCatalogName,
					cbCatalogName,
					pSchemaName,
					cbSchemaName,
					pTableName,
					cbTableName,
					pTableType,
					cbTableType);
			}

		}

		setCatalogQueryBuf(pStmt, szCatalogQuery);
		rc = RsExecute::RS_SQLExecDirect(phstmt, (SQLCHAR *)szCatalogQuery, SQL_NTS, TRUE, FALSE, FALSE, TRUE);
		resetCatalogQueryFlag(pStmt);
	}

    return rc;
}