Hi all,
If it helps, I created a reusable object that runs a query on Databricks (there are two actions, one for a personal token, the other for a token generated by Service Principal). Here is the code:
<process name="VBO - Databricks" version="1.0" bpversion="7.1.0.62280" narrative="" byrefcollection="true" type="object" runmode="Exclusive" preferredid="a89c02ea-a295-4848-b504-a2afe92a5e7e">
<appdef>
<element name="Application Root">
<id>a1fcd9f9-3d26-4f70-bcc0-8406d53a2f05</id>
<type>Application</type>
<basetype>Application</basetype>
<datatype>unknown</datatype>
<diagnose>False</diagnose>
</element>
</appdef>
<view>
<camerax>0</camerax>
<cameray>0</cameray>
<zoom version="2">1.25</zoom>
</view>
<preconditions />
<endpoint narrative="" />
<subsheet subsheetid="7d7495b5-ea2b-424a-aae0-3c029b92f2a9" type="CleanUp" published="True">
<name>Clean Up</name>
<view>
<camerax>0</camerax>
<cameray>0</cameray>
<zoom version="2">1.25</zoom>
</view>
</subsheet>
<subsheet subsheetid="9cb7bf9b-8ba4-45f2-b334-fc34ba39707a" type="Normal" published="False">
<name>Authentication</name>
<view>
<camerax>0</camerax>
<cameray>21</cameray>
<zoom version="2">1.25</zoom>
</view>
</subsheet>
<subsheet subsheetid="8e5d6e27-2067-4108-a3de-c6d32385476c" type="Normal" published="True">
<name>Execute Query</name>
<view>
<camerax>-111</camerax>
<cameray>243</cameray>
<zoom version="2">1.25</zoom>
</view>
</subsheet>
<subsheet subsheetid="fa900c6f-ef74-4b80-a2e5-f70e341de476" type="Normal" published="True">
<name>Execute Query - Using Token</name>
<view>
<camerax>-111</camerax>
<cameray>96</cameray>
<zoom version="2">1.25</zoom>
</view>
</subsheet>
<stage stageid="ea40e4ef-0578-444a-93d6-cf433c09b609" name="Start" type="Start">
<loginhibit />
<display x="15" y="-105" />
<onsuccess>1fba778b-777b-4bb2-8996-1fc62fc8fcd2</onsuccess>
</stage>
<stage stageid="1fba778b-777b-4bb2-8996-1fc62fc8fcd2" name="End" type="End">
<loginhibit />
<display x="15" y="90" />
</stage>
<stage stageid="f34ba72c-ee5c-4e66-9417-d7196dd2134a" name="Stage1" type="ProcessInfo">
<display x="-195" y="-105" w="150" h="90" />
<references>
<reference>System.dll</reference>
<reference>System.Data.dll</reference>
<reference>System.Xml.dll</reference>
<reference>System.Drawing.dll</reference>
<reference>System.Net.Http.dll</reference>
<reference>EPPlus.dll</reference>
<reference>ClosedXML.dll</reference>
<reference>netstandard.dll</reference>
<reference>System.Core.dll</reference>
<reference>System.Net.Http.Json.dll</reference>
<reference>Newtonsoft.Json.dll</reference>
<reference>System.Windows.Forms.dll</reference>
<reference>System.Net.Http.dll</reference>
</references>
<imports>
<import>System</import>
<import>System.Drawing</import>
<import>System.Data</import>
<import>System.Net.Http</import>
<import>System.Text</import>
<import>ClosedXML.Excel</import>
<import>OfficeOpenXml</import>
<import>System.Collections.Generic</import>
<import>System.Linq</import>
<import>System.IO</import>
<import>Newtonsoft.Json</import>
<import>Newtonsoft.Json.Linq</import>
<import>System.Windows.Forms</import>
<import>System.Net.Http.Headers</import>
</imports>
<language>csharp</language>
<globalcode><![CDATA[]]></globalcode>
<code><![CDATA[public class DataTableToExcel
{
public void ExportToExcel(DataTable dataTable, string filePath, string sheet)
{
// Configura EPPlus per usare la licenza non commerciale
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add(sheet);
// Aggiungi le intestazioni delle colonne
for (int col = 0; col < dataTable.Columns.Count; col++)
{
worksheet.Cells[1, col + 1].Value = dataTable.Columns[col].ColumnName;
}
// Aggiungi i dati delle righe
worksheet.Cells["A2"].LoadFromDataTable(dataTable, false);
// Salva il file Excel
var fileInfo = new FileInfo(filePath);
package.SaveAs(fileInfo);
}
}
}
public class Column
{
public string name { get; set; }
}
public class Row
{
public List<string> values { get; set; }
}
public class JsonResponse
{
public List<Column> columns { get; set; }
public List<Row> rows { get; set; }
}
public static DataTable GenerateDataTableFromJson(string json)
{
JObject jsonObject = JObject.Parse(json);
JArray columns = (JArray)jsonObject["manifest"]["schema"]["columns"];
JArray dataArray = (JArray)jsonObject["result"]["data_array"];
DataTable dataTable = new DataTable();
foreach (var column in columns)
{
dataTable.Columns.Add(column["name"].ToString(), typeof(string));
}
foreach (var row in dataArray)
{
DataRow dataRow = dataTable.NewRow();
for (int i = 0; i < columns.Count; i++)
{
dataRow[i] = row[i].ToString();
}
dataTable.Rows.Add(dataRow);
}
return dataTable;
}
public static string EscapeForJson(string s)
{
if (s == null) return "";
return s.Replace("\\", "\\\\").Replace("\"", "\\\"");
}
]]></code>
</stage>
<stage stageid="ce38e7ce-fcf1-4e63-bd70-44a2babf6a61" name="Clean Up" type="SubSheetInfo">
<subsheetid>7d7495b5-ea2b-424a-aae0-3c029b92f2a9</subsheetid>
<display x="-195" y="-105" w="150" h="90" />
</stage>
<stage stageid="6638295e-5a03-4485-84f4-0be42967f3be" name="Start" type="Start">
<subsheetid>7d7495b5-ea2b-424a-aae0-3c029b92f2a9</subsheetid>
<loginhibit />
<display x="15" y="-105" />
<onsuccess>9e0c8841-53a6-4607-ad35-b1d9f8b571d7</onsuccess>
</stage>
<stage stageid="9e0c8841-53a6-4607-ad35-b1d9f8b571d7" name="End" type="End">
<subsheetid>7d7495b5-ea2b-424a-aae0-3c029b92f2a9</subsheetid>
<loginhibit />
<display x="15" y="90" />
</stage>
<stage stageid="a7ffe0ff-6bed-410a-8542-627fac718426" name="Execute Query" type="SubSheetInfo">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-195" y="-105" w="150" h="90" />
</stage>
<stage stageid="7f49a903-a4c5-4669-b7e3-c8b900154c68" name="Start" type="Start">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-60" y="-135" />
<inputs>
<input type="text" name="baseUrl" stage="baseUrl" />
<input type="text" name="accessToken" stage="accessToken" />
<input type="text" name="warehouseId" stage="warehouseId" />
<input type="text" name="sqlQuery" stage="sqlQuery" />
<input type="flag" name="CreateExcel" stage="CreateExcel" />
<input type="text" name="FilepathXLSX" stage="FilepathXLSX" />
<input type="text" name="SheetName" stage="SheetName" />
</inputs>
<onsuccess>d0350ab4-99aa-4763-8c78-887721f4a3a5</onsuccess>
</stage>
<stage stageid="6a16195e-41c8-4e52-8625-061243db0811" name="End" type="End">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-60" y="345" />
<outputs>
<output type="flag" name="Success" stage="Success" />
<output type="text" name="Error Message" stage="Error Message" />
<output type="collection" name="Report" stage="Report" />
</outputs>
</stage>
<stage stageid="882d594d-6359-4c08-9c68-adb46b927cc7" name="" type="Note">
<subsheetid>7d7495b5-ea2b-424a-aae0-3c029b92f2a9</subsheetid>
<narrative>Clean Up Page
This is an optional page where you might choose to perform some finalisation (or "cleanup") tasks as your business object is closed down.
The cleanup action will be called automatically immediately after closing your business object at the end of a business process.
You will not be able to call this action from a business process, nor will it be called at any other time than before the disposal of the business object.</narrative>
<display x="-180" y="60" w="180" h="230" />
</stage>
<stage stageid="211de8a5-16c7-48bf-bff2-3e8859a8d124" name="" type="Note">
<narrative>Initialise Page
This is an optional page where you might choose to perform some initialisation tasks after your business object is loaded.
The initialise action will be called automatically immediately after loading your business object.
You will not be able to call this action from a business process, nor will it be called at any other time than after the creation of the object.</narrative>
<display x="-180" y="60" w="180" h="230" />
</stage>
<stage stageid="d0350ab4-99aa-4763-8c78-887721f4a3a5" name="Call API" type="Code">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-60" y="-75" />
<inputs>
<input type="text" name="baseUrl" expr="[baseUrl]" />
<input type="text" name="accessToken" expr="[accessToken]" />
<input type="text" name="warehouseId" expr="[warehouseId]" />
<input type="text" name="sqlQuery" expr="[sqlQuery]" />
</inputs>
<outputs>
<output type="flag" name="Success" stage="Success" />
<output type="text" name="ErrorMessage" stage="Error Message" />
<output type="text" name="JSONOutput" stage="JSONOutput" />
</outputs>
<onsuccess>5555a2e6-2d06-4da2-b986-60516c04f8c4</onsuccess>
<code><![CDATA[Success = false;
ErrorMessage = "";
JSONOutput = "";
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, baseUrl)
{
Content = new StringContent(
$"{{\"statement\":\"{sqlQuery}\", \"warehouse_id\":\"{warehouseId}\", \"timeout_seconds\":600}}",
Encoding.UTF8,
"application/json"
)
};
request.Headers.Add("Authorization", $"Bearer {accessToken}"); // Invia la richiesta
HttpResponseMessage response = client.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
string responseBody = response.Content.ReadAsStringAsync().Result;
Success = true;
JSONOutput = responseBody;
}
else
{
string responseBody = response.Content.ReadAsStringAsync().Result;
ErrorMessage = responseBody;
}
]]></code>
</stage>
<stage stageid="8e8901e4-0469-467c-ba32-ef8872e06bd4" name="baseUrl" type="Data">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-165" y="30" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="dccd3340-c59f-4c07-9cf0-6b2158a0b15c" name="accessToken" type="Data">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-225" y="30" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="a37d696c-f22a-42d2-926e-972ba737ca40" name="warehouseId" type="Data">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-165" y="-15" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="bd29c410-6809-46ee-ba90-4913e5c23721" name="sqlQuery" type="Data">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-225" y="-15" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="23e4c765-3cad-483e-b764-22c0b9fa4986" name="Success" type="Data">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-165" y="360" />
<datatype>flag</datatype>
<initialvalue>False</initialvalue>
<private />
<alwaysinit />
</stage>
<stage stageid="c9bef68e-b917-4f91-a8f3-850be2935e93" name="Error Message" type="Data">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-225" y="360" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="a4f71191-c150-4bc5-a71c-1407b88ea104" name="JSONOutput" type="Data">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-225" y="195" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="23680203-a356-4f4a-9aa5-11ec8d787164" name="Report" type="Collection">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-225" y="405" />
<datatype>collection</datatype>
<private />
<alwaysinit />
</stage>
<stage stageid="2b95b981-f6a3-46d2-ac2f-c3bf37e109aa" name="Convert JSON" type="Code">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-60" y="45" />
<inputs>
<input type="text" name="json" expr="[JSONOutput]" />
</inputs>
<outputs>
<output type="flag" name="Success" stage="Success" />
<output type="text" name="ErrorMessage" stage="Error Message" />
<output type="collection" name="dataTable" stage="Report" />
</outputs>
<onsuccess>081c9bf2-4828-47ba-9f88-ee45a75f8735</onsuccess>
<code><![CDATA[Success = false;
ErrorMessage = "";
dataTable = null;
dataTable = new DataTable();
try
{
dataTable = GenerateDataTableFromJson(json);
Success = true;
}
catch (Exception ex)
{
Success = false;
ErrorMessage = ex.Message;
}
]]></code>
</stage>
<stage stageid="6f826340-a4b0-4a90-a21b-b7e83d2c3b64" name="Inputs" type="Block">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-270" y="-45" w="150" h="195" />
<font family="Segoe UI" size="10" style="Regular" color="7FB2E5" />
</stage>
<stage stageid="fc658c67-57fc-4741-81e3-420dee311aad" name="Local" type="Block">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-270" y="165" w="150" h="150" />
<font family="Segoe UI" size="10" style="Regular" color="FFFF00" />
</stage>
<stage stageid="69e8baa0-51a9-4cb0-8102-628d715d54fd" name="Outputs" type="Block">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-270" y="330" w="150" h="105" />
<font family="Segoe UI" size="10" style="Regular" color="FF00FF" />
</stage>
<stage stageid="3d0bd6c8-bfea-4f19-b1f0-17af6082fd95" name="FilepathXLSX" type="Data">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-165" y="75" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="6fce1fed-aed7-4be8-98a7-47cd4d387274" name="CreateExcel" type="Data">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-225" y="75" />
<datatype>flag</datatype>
<initialvalue>False</initialvalue>
<private />
<alwaysinit />
</stage>
<stage stageid="4a1251fb-c3ba-49fa-82e5-4364fec79357" name="Create Excel" type="Code">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-60" y="225" />
<inputs>
<input type="collection" name="DatatableResult" expr="[Report]" />
<input type="text" name="Filepath" expr="[FilepathXLSX]" />
<input type="text" name="SheetName" expr="[SheetName]" />
</inputs>
<outputs>
<output type="flag" name="Success" stage="Success" />
<output type="text" name="ErrorMessage" stage="Error Message" />
</outputs>
<onsuccess>943d0920-2cf6-4da3-9b48-9a5af41f847f</onsuccess>
<code><![CDATA[Success = false;
ErrorMessage = "";
try
{
DataTableToExcel exporter = new DataTableToExcel();
exporter.ExportToExcel(DatatableResult, Filepath, SheetName);
Success = true;
}
catch (Exception ex)
{
Success = false;
ErrorMessage = ex.Message;
}]]></code>
</stage>
<stage stageid="3f15a13e-c6d9-4309-b03c-b84634339a44" name="[CreateExcel] = True" type="Decision">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-60" y="165" />
<decision expression="[CreateExcel] = True" />
<ontrue>4a1251fb-c3ba-49fa-82e5-4364fec79357</ontrue>
<onfalse>aff1fb43-83dd-411b-895e-121a6e9aaa67</onfalse>
</stage>
<stage stageid="aff1fb43-83dd-411b-895e-121a6e9aaa67" name="Anchor1" type="Anchor">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="90" y="165" w="10" h="10" />
<onsuccess>de02cbf6-bc09-4036-9c44-61fe6f59330b</onsuccess>
</stage>
<stage stageid="7d038089-d0d0-47d6-9567-ff7fbd4e2ad2" name="Anchor2" type="Anchor">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="90" y="345" w="10" h="10" />
<onsuccess>6a16195e-41c8-4e52-8625-061243db0811</onsuccess>
</stage>
<stage stageid="8d301f0a-94c3-4852-a216-f252b27166c3" name="SheetName" type="Data">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<display x="-225" y="120" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="5555a2e6-2d06-4da2-b986-60516c04f8c4" name="[Success] = True" type="Decision">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-60" y="-15" />
<decision expression="[Success] = True" />
<ontrue>2b95b981-f6a3-46d2-ac2f-c3bf37e109aa</ontrue>
<onfalse>25ddca11-d42c-4ac1-bfeb-590504da586b</onfalse>
</stage>
<stage stageid="081c9bf2-4828-47ba-9f88-ee45a75f8735" name="[Success] = True" type="Decision">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-60" y="105" />
<decision expression="[Success] = True" />
<ontrue>3f15a13e-c6d9-4309-b03c-b84634339a44</ontrue>
<onfalse>d9b92af7-75ca-4170-9a32-2981d266cc24</onfalse>
</stage>
<stage stageid="25ddca11-d42c-4ac1-bfeb-590504da586b" name="Set Error Message" type="Calculation">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="30" y="-15" />
<onsuccess>9708dd42-1db3-4ae3-809d-1513db8538f9</onsuccess>
<calculation expression=""Error in API Call: "&[Error Message]" stage="Error Message" />
</stage>
<stage stageid="d9b92af7-75ca-4170-9a32-2981d266cc24" name="Set Error Message" type="Calculation">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="30" y="105" />
<onsuccess>5dc509e2-1dea-4ae3-ae96-918a7a64f060</onsuccess>
<calculation expression=""Error in JSON Conversion: "&[Error Message]" stage="Error Message" />
</stage>
<stage stageid="943d0920-2cf6-4da3-9b48-9a5af41f847f" name="[Success] = True" type="Decision">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="-60" y="285" />
<decision expression="[Success] = True" />
<ontrue>6a16195e-41c8-4e52-8625-061243db0811</ontrue>
<onfalse>fc1ca4c2-0045-4d9d-ad88-61abf950a75c</onfalse>
</stage>
<stage stageid="fc1ca4c2-0045-4d9d-ad88-61abf950a75c" name="Set Error Message" type="Calculation">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="30" y="285" />
<onsuccess>de02cbf6-bc09-4036-9c44-61fe6f59330b</onsuccess>
<calculation expression=""Error in Create Excel: "&[Error Message]" stage="Error Message" />
</stage>
<stage stageid="9708dd42-1db3-4ae3-809d-1513db8538f9" name="Anchor3" type="Anchor">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="90" y="-15" w="10" h="10" />
<onsuccess>5dc509e2-1dea-4ae3-ae96-918a7a64f060</onsuccess>
</stage>
<stage stageid="5dc509e2-1dea-4ae3-ae96-918a7a64f060" name="Anchor4" type="Anchor">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="90" y="105" w="10" h="10" />
<onsuccess>aff1fb43-83dd-411b-895e-121a6e9aaa67</onsuccess>
</stage>
<stage stageid="de02cbf6-bc09-4036-9c44-61fe6f59330b" name="Anchor5" type="Anchor">
<subsheetid>8e5d6e27-2067-4108-a3de-c6d32385476c</subsheetid>
<loginhibit />
<display x="90" y="285" w="10" h="10" />
<onsuccess>7d038089-d0d0-47d6-9567-ff7fbd4e2ad2</onsuccess>
</stage>
<stage stageid="8848462a-85fd-4a3a-bc39-15398ec8475f" name="Authentication" type="SubSheetInfo">
<subsheetid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</subsheetid>
<display x="-195" y="-105" w="150" h="90" />
</stage>
<stage stageid="7f4050b6-af0c-44aa-afa5-b7d0fd9f4f1c" name="Start" type="Start">
<subsheetid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</subsheetid>
<loginhibit />
<display x="-60" y="-135" />
<onsuccess>8c424f0b-43e3-49bd-9deb-97c9e5ded003</onsuccess>
</stage>
<stage stageid="aace0190-ea26-4a19-9ebe-9048a002664e" name="End" type="End">
<subsheetid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</subsheetid>
<loginhibit />
<display x="-60" y="-15" />
<outputs>
<output type="text" name="AccessToken" stage="AccessToken" />
</outputs>
</stage>
<stage stageid="baa4ea76-41aa-46e6-8a66-4920d8f05d99" name="Inputs" type="Block">
<subsheetid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</subsheetid>
<loginhibit />
<display x="-270" y="-45" w="150" h="195" />
<font family="Segoe UI" size="10" style="Regular" color="7FB2E5" />
</stage>
<stage stageid="0f8f7e0c-8f73-402c-9601-9443b4f6827e" name="Local" type="Block">
<subsheetid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</subsheetid>
<loginhibit />
<display x="-270" y="165" w="150" h="150" />
<font family="Segoe UI" size="10" style="Regular" color="FFFF00" />
</stage>
<stage stageid="7066e6a3-cb35-4561-bc57-fb6785819432" name="Outputs" type="Block">
<subsheetid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</subsheetid>
<loginhibit />
<display x="-270" y="330" w="150" h="105" />
<font family="Segoe UI" size="10" style="Regular" color="FF00FF" />
</stage>
<stage stageid="79280ca6-6232-452b-b7b2-8810f0ff1547" name="TenantID" type="Data">
<subsheetid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</subsheetid>
<loginhibit />
<display x="-195" y="-15" w="120" h="30" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="5e4e3fc9-859a-4eeb-b1bf-3cfedc42bb8a" name="ClientId" type="Data">
<subsheetid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</subsheetid>
<loginhibit />
<display x="-195" y="30" w="120" h="30" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="3b5f25be-6542-4ee9-aae5-7e8174743bb3" name="ClientSecret" type="Data">
<subsheetid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</subsheetid>
<loginhibit />
<display x="-195" y="75" w="120" h="30" />
<datatype>password</datatype>
<initialvalueenc>
</initialvalueenc>
<private />
<alwaysinit />
</stage>
<stage stageid="8c424f0b-43e3-49bd-9deb-97c9e5ded003" name="Get Token" type="Code">
<subsheetid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</subsheetid>
<loginhibit />
<display x="-60" y="-75" />
<inputs>
<input type="text" name="TenantID" expr="[TenantID]" />
<input type="text" name="ClientId" expr="[ClientId]" />
<input type="password" name="ClientSecret" expr="[ClientSecret]" />
</inputs>
<outputs>
<output type="text" name="AccessToken" stage="AccessToken" />
</outputs>
<onsuccess>aace0190-ea26-4a19-9ebe-9048a002664e</onsuccess>
<code><![CDATA[
using (var httpClient = new HttpClient())
{
var form = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", ClientId),
new KeyValuePair<string, string>("client_secret", ClientSecret),
new KeyValuePair<string, string>("grant_type", "client_credentials"),
// Scope corretto per Azure Databricks (AAD resource + /.default)
new KeyValuePair<string, string>("scope", "2ff814a6-3304-4ab8-85cb-cd0e6f879c1d/.default")
});
var resp = httpClient.PostAsync(tokenUrl, form).GetAwaiter().GetResult();
string body = resp.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (!resp.IsSuccessStatusCode)
{
throw new Exception($"Token request failed ({resp.StatusCode}): {body}");
}
var json = JObject.Parse(body);
string accessToken = json["access_token"]?.ToString();
if (string.IsNullOrEmpty(accessToken))
throw new Exception("access_token missing in token response");
AccessToken = accessToken;
}
]]></code>
</stage>
<stage stageid="46d709ef-5c75-4394-83b0-78471c8c463a" name="AccessToken" type="Data">
<subsheetid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</subsheetid>
<display x="-225" y="360" />
<datatype>text</datatype>
<initialvalue />
<alwaysinit />
</stage>
<stage stageid="4e76287c-26c7-45de-a165-1f3257d8760f" name="Execute Query - Using Token" type="SubSheetInfo">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-195" y="-105" w="150" h="90" />
</stage>
<stage stageid="2d3a1314-19e9-4398-9259-4ec602b70f7e" name="Start" type="Start">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-60" y="-135" />
<inputs>
<input type="text" name="databricksUrl" stage="databricksUrl" />
<input type="text" name="warehouseId" stage="warehouseId" />
<input type="text" name="sqlQuery" stage="sqlQuery" />
<input type="flag" name="CreateExcel" stage="CreateExcel" />
<input type="text" name="FilepathXLSX" stage="FilepathXLSX" />
<input type="text" name="SheetName" stage="SheetName" />
</inputs>
<onsuccess>33ac5062-313a-408b-a962-0eb8eab9b6a4</onsuccess>
</stage>
<stage stageid="d1c909a0-c003-41a6-8d16-835dcb19fd7c" name="End" type="End">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-60" y="405" />
<outputs>
<output type="flag" name="Success" stage="Success" />
<output type="text" name="Error Message" stage="Error Message" />
<output type="collection" name="Report" stage="Report" />
</outputs>
</stage>
<stage stageid="753bbed9-7194-48db-86f7-2047f2dd218f" name="accessToken" type="Data">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-165" y="195" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="74a6a9eb-ee35-4699-84ad-329239d1058f" name="warehouseId" type="Data">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-165" y="-15" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="5e43ad48-cc52-41bb-89c4-6596788a19dd" name="sqlQuery" type="Data">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-225" y="-15" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="d4f9c706-65f0-4c79-8779-a00d9d9529a3" name="Success" type="Data">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-165" y="360" />
<datatype>flag</datatype>
<initialvalue>False</initialvalue>
<private />
<alwaysinit />
</stage>
<stage stageid="536e4740-8f66-4f28-b651-be23fdef263f" name="Error Message" type="Data">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-225" y="360" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="4b5e9e32-cc4c-468a-b1d1-b96bdfab941f" name="JSONOutput" type="Data">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-225" y="195" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="23766df5-bdba-449f-8d36-858278c8d97e" name="Report" type="Collection">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-225" y="405" />
<datatype>collection</datatype>
<private />
<alwaysinit />
</stage>
<stage stageid="767269e4-2267-4297-a3c9-d97409e501de" name="Convert JSON Token" type="Code">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-60" y="105" />
<inputs>
<input type="text" name="json" expr="[JSONOutput]" />
</inputs>
<outputs>
<output type="flag" name="Success" stage="Success" />
<output type="text" name="ErrorMessage" stage="Error Message" />
<output type="collection" name="dataTable" stage="Report" />
</outputs>
<onsuccess>d88bcda0-42b4-4302-ba8c-e642949c5a69</onsuccess>
<code><![CDATA[Success = false;
ErrorMessage = "";
dataTable = null;
dataTable = new DataTable();
try
{
dataTable = GenerateDataTableFromJson(json);
Success = true;
}
catch (Exception ex)
{
Success = false;
ErrorMessage = ex.Message;
}
]]></code>
</stage>
<stage stageid="33c5e16f-fa4e-4750-9e61-14e9f79eb243" name="Inputs" type="Block">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-270" y="-45" w="150" h="195" />
<font family="Segoe UI" size="10" style="Regular" color="7FB2E5" />
</stage>
<stage stageid="ebf2fea7-8b77-44c8-a000-9038213e3e34" name="Local" type="Block">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-270" y="165" w="150" h="150" />
<font family="Segoe UI" size="10" style="Regular" color="FFFF00" />
</stage>
<stage stageid="deb7307c-8680-4762-9dc1-5b7d5600729f" name="Outputs" type="Block">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-270" y="330" w="150" h="105" />
<font family="Segoe UI" size="10" style="Regular" color="FF00FF" />
</stage>
<stage stageid="5529a3ca-016c-44d8-94b1-56377f9b40fd" name="FilepathXLSX" type="Data">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-165" y="75" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="5add693a-51ef-4f02-a9c8-633e927ee473" name="CreateExcel" type="Data">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-225" y="75" />
<datatype>flag</datatype>
<initialvalue>False</initialvalue>
<private />
<alwaysinit />
</stage>
<stage stageid="61a50860-9a73-4cbd-8307-274af6b1cff2" name="Create Excel Token" type="Code">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-60" y="285" />
<inputs>
<input type="collection" name="DatatableResult" expr="[Report]" />
<input type="text" name="Filepath" expr="[FilepathXLSX]" />
<input type="text" name="SheetName" expr="[SheetName]" />
</inputs>
<outputs>
<output type="flag" name="Success" stage="Success" />
<output type="text" name="ErrorMessage" stage="Error Message" />
</outputs>
<onsuccess>d0c941a8-7e1a-4167-b165-ae1bae998acf</onsuccess>
<code><![CDATA[Success = false;
ErrorMessage = "";
try
{
DataTableToExcel exporter = new DataTableToExcel();
exporter.ExportToExcel(DatatableResult, Filepath, SheetName);
Success = true;
}
catch (Exception ex)
{
Success = false;
ErrorMessage = ex.Message;
}]]></code>
</stage>
<stage stageid="e7d0172b-74d8-4261-a310-976261f28845" name="[CreateExcel] = True" type="Decision">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-60" y="225" />
<decision expression="[CreateExcel] = True" />
<ontrue>61a50860-9a73-4cbd-8307-274af6b1cff2</ontrue>
<onfalse>e5242eaf-7df1-445a-be16-359ff2906db9</onfalse>
</stage>
<stage stageid="e5242eaf-7df1-445a-be16-359ff2906db9" name="Anchor1" type="Anchor">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="90" y="225" w="10" h="10" />
<onsuccess>6f7ea0aa-ca84-4bc5-b2cb-b00a3f5a11c1</onsuccess>
</stage>
<stage stageid="c5eff911-30f7-4e00-bf78-bd2290970310" name="Anchor2" type="Anchor">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="90" y="405" w="10" h="10" />
<onsuccess>d1c909a0-c003-41a6-8d16-835dcb19fd7c</onsuccess>
</stage>
<stage stageid="d2f2e471-9a3f-4b66-b87a-c3d790bfbcb0" name="SheetName" type="Data">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-165" y="30" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="ad69bfb0-e52b-47f0-a648-5f1e094fcf37" name="[Success] = True" type="Decision">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-60" y="45" />
<decision expression="[Success] = True" />
<ontrue>767269e4-2267-4297-a3c9-d97409e501de</ontrue>
<onfalse>c0a9ca49-ff4e-441d-9650-da100bcf6bad</onfalse>
</stage>
<stage stageid="d88bcda0-42b4-4302-ba8c-e642949c5a69" name="[Success] = True" type="Decision">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-60" y="165" />
<decision expression="[Success] = True" />
<ontrue>e7d0172b-74d8-4261-a310-976261f28845</ontrue>
<onfalse>04d9f303-e399-4bb3-93fa-3ce536aa55a1</onfalse>
</stage>
<stage stageid="c0a9ca49-ff4e-441d-9650-da100bcf6bad" name="Set Error Message" type="Calculation">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="30" y="45" />
<onsuccess>0f46bfec-9fc3-4b45-9073-b2a2feebbbe3</onsuccess>
<calculation expression=""Error in API Call: "&[Error Message]" stage="Error Message" />
</stage>
<stage stageid="04d9f303-e399-4bb3-93fa-3ce536aa55a1" name="Set Error Message" type="Calculation">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="30" y="165" />
<onsuccess>93dfc5a7-0afe-4188-9a40-fb7de4b3b993</onsuccess>
<calculation expression=""Error in JSON Conversion: "&[Error Message]" stage="Error Message" />
</stage>
<stage stageid="d0c941a8-7e1a-4167-b165-ae1bae998acf" name="[Success] = True" type="Decision">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-60" y="345" />
<decision expression="[Success] = True" />
<ontrue>d1c909a0-c003-41a6-8d16-835dcb19fd7c</ontrue>
<onfalse>33d8e73b-b167-41a9-8606-25057a305ddc</onfalse>
</stage>
<stage stageid="33d8e73b-b167-41a9-8606-25057a305ddc" name="Set Error Message" type="Calculation">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="30" y="345" />
<onsuccess>6f7ea0aa-ca84-4bc5-b2cb-b00a3f5a11c1</onsuccess>
<calculation expression=""Error in Create Excel: "&[Error Message]" stage="Error Message" />
</stage>
<stage stageid="0f46bfec-9fc3-4b45-9073-b2a2feebbbe3" name="Anchor3" type="Anchor">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="90" y="45" w="10" h="10" />
<onsuccess>93dfc5a7-0afe-4188-9a40-fb7de4b3b993</onsuccess>
</stage>
<stage stageid="93dfc5a7-0afe-4188-9a40-fb7de4b3b993" name="Anchor4" type="Anchor">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="90" y="165" w="10" h="10" />
<onsuccess>e5242eaf-7df1-445a-be16-359ff2906db9</onsuccess>
</stage>
<stage stageid="6f7ea0aa-ca84-4bc5-b2cb-b00a3f5a11c1" name="Anchor5" type="Anchor">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="90" y="345" w="10" h="10" />
<onsuccess>c5eff911-30f7-4e00-bf78-bd2290970310</onsuccess>
</stage>
<stage stageid="10d34c6c-df8b-4d15-9a20-6ae62ee2bb83" name="Call API Token" type="Code">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-60" y="-15" />
<inputs>
<input type="text" name="databricksUrl" expr="[databricksUrl]" />
<input type="text" name="accessToken" expr="[accessToken]" />
<input type="text" name="warehouseId" expr="[warehouseId]" />
<input type="text" name="sqlQuery" expr="[sqlQuery]" />
</inputs>
<outputs>
<output type="flag" name="Success" stage="Success" />
<output type="text" name="ErrorMessage" stage="Error Message" />
<output type="text" name="JSONOutput" stage="JSONOutput" />
</outputs>
<onsuccess>ad69bfb0-e52b-47f0-a648-5f1e094fcf37</onsuccess>
<code><![CDATA[Success = false;
ErrorMessage = "";
JSONOutput = "";
try
{
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
var payload = new
{
statement = sqlQuery,
warehouse_id = warehouseId,
wait_timeout = "30s"
};
var content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json");
var resp = httpClient.PostAsync(databricksUrl, content).GetAwaiter().GetResult();
string body = resp.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (!resp.IsSuccessStatusCode)
{
throw new Exception($"Query failed ({resp.StatusCode}): {body}");
}
else
{
JSONOutput = body;
Success = true;
}
}
}
catch (Exception ex)
{
Success = false;
ErrorMessage = ex.ToString();
}
]]></code>
</stage>
<stage stageid="cb0efb85-278a-4cf1-a80d-b99a7b2439f8" name="databricksUrl" type="Data">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<display x="-225" y="30" />
<datatype>text</datatype>
<initialvalue />
<private />
<alwaysinit />
</stage>
<stage stageid="33ac5062-313a-408b-a962-0eb8eab9b6a4" name="Authentication" type="SubSheet">
<subsheetid>fa900c6f-ef74-4b80-a2e5-f70e341de476</subsheetid>
<loginhibit />
<display x="-60" y="-75" />
<outputs>
<output type="text" name="AccessToken" friendlyname="AccessToken" stage="accessToken" />
</outputs>
<onsuccess>10d34c6c-df8b-4d15-9a20-6ae62ee2bb83</onsuccess>
<processid>9cb7bf9b-8ba4-45f2-b334-fc34ba39707a</processid>
</stage>
</process>
Simone