| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| //--------------------------------------------------------------------------- |
| // @filename: |
| // funcs.cpp |
| // |
| // @doc: |
| // API for invoking optimizer using GPDB udfs |
| // |
| // @test: |
| // |
| // |
| //--------------------------------------------------------------------------- |
| |
| #define ALLOW_appendStringInfo |
| |
| #include <sys/stat.h> |
| #include "gpopt/utils/nodeutils.h" |
| #include "gpopt/utils/CCatalogUtils.h" |
| #include "gpopt/utils/COptTasks.h" |
| |
| #include "gpos/_api.h" |
| #include "gpos/io/CFileReader.h" |
| #include "gpos/io/CFileWriter.h" |
| #include "gpopt/gpdbwrappers.h" |
| |
| extern "C" { |
| |
| PG_MODULE_MAGIC_CPP; |
| |
| #undef PG_DETOAST_DATUM |
| #define PG_DETOAST_DATUM(datum) \ |
| gpdb::PvlenDetoastDatum((struct varlena *) gpdb::PvPointerFromDatum(datum)) |
| |
| #undef PG_RETURN_POINTER |
| #define PG_RETURN_POINTER(x) return gpdb::DDatumFromPointer(x) |
| |
| #undef PG_RETURN_UINT32 |
| #define PG_RETURN_UINT32(x) return gpdb::DDatumFromUint32(x) |
| |
| #undef PG_RETURN_INT32 |
| #define PG_RETURN_INT32(x) return gpdb::DDatumFromInt32(x) |
| |
| // by value |
| |
| PG_FUNCTION_INFO_V1(DumpPlan); |
| PG_FUNCTION_INFO_V1(RestorePlan); |
| PG_FUNCTION_INFO_V1(DumpPlanToFile); |
| PG_FUNCTION_INFO_V1(RestorePlanFromFile); |
| PG_FUNCTION_INFO_V1(DumpPlanDXL); |
| PG_FUNCTION_INFO_V1(DumpPlanToDXLFile); |
| PG_FUNCTION_INFO_V1(RestorePlanDXL); |
| PG_FUNCTION_INFO_V1(RestorePlanFromDXLFile); |
| PG_FUNCTION_INFO_V1(DumpMDObjDXL); |
| PG_FUNCTION_INFO_V1(DumpCatalogDXL); |
| PG_FUNCTION_INFO_V1(DumpRelStatsDXL); |
| PG_FUNCTION_INFO_V1(DumpMDCastDXL); |
| PG_FUNCTION_INFO_V1(DumpMDScCmpDXL); |
| |
| PG_FUNCTION_INFO_V1(DumpQuery); |
| PG_FUNCTION_INFO_V1(RestoreQuery); |
| PG_FUNCTION_INFO_V1(DumpQueryToFile); |
| PG_FUNCTION_INFO_V1(RestoreQueryFromFile); |
| PG_FUNCTION_INFO_V1(DumpQueryDXL); |
| PG_FUNCTION_INFO_V1(DumpQueryToDXLFile); |
| PG_FUNCTION_INFO_V1(DumpQueryFromFileToDXLFile); |
| PG_FUNCTION_INFO_V1(RestoreQueryDXL); |
| PG_FUNCTION_INFO_V1(RestoreQueryFromDXLFile); |
| PG_FUNCTION_INFO_V1(DisableXform); |
| PG_FUNCTION_INFO_V1(EnableXform); |
| PG_FUNCTION_INFO_V1(LibraryVersion); |
| |
| PG_FUNCTION_INFO_V1(Optimize); |
| |
| PG_FUNCTION_INFO_V1(EvalExprFromDXLFile); |
| PG_FUNCTION_INFO_V1(OptimizeMinidumpFromFile); |
| PG_FUNCTION_INFO_V1(ExecuteMinidumpFromFile); |
| } // end extern C |
| |
| |
| static PlannedStmt *planQuery(char *szSqlText); |
| static Query *parseSQL(char *szSqlText); |
| static char *getQueryBinary(char *szSqlText, size_t *piLength); |
| static char *getPlannedStmtBinary(char *szSqlText, size_t *piLength); |
| static int extractFrozenPlanAndExecute(char *pcSerializedPS); |
| static int extractFrozenQueryPlanAndExecute(char *pcQuery); |
| static int executeXMLPlan(char *szXml); |
| static int executeXMLQuery(char *szXml); |
| static int translateQueryToFile(char *szSqlText, char *szFilename); |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // parseSQL |
| // |
| // @doc: |
| // Parse a query given as SQL text. |
| // Input: |
| // szSqlText - SQL query |
| // Output: |
| // query object |
| // |
| //--------------------------------------------------------------------------- |
| |
| static Query *parseSQL(char *szSqlText) |
| { |
| Assert(szSqlText); |
| Assert(szSqlText); |
| |
| List *plQueryTree = pg_parse_and_rewrite(szSqlText, NULL, 0); |
| |
| if (1 != gpdb::UlListLength(plQueryTree)) |
| { |
| elog(ERROR, "problem parsing query %s", szSqlText); |
| } |
| |
| Query *pquery = (Query *) lfirst(gpdb::PlcListHead(plQueryTree)); |
| |
| return pquery; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // PlannedStmt |
| // |
| // @doc: |
| // Plan a query given as SQL text. |
| // Input: |
| // szSqlText - SQL query |
| // Output: |
| // planned stmt |
| // |
| //--------------------------------------------------------------------------- |
| |
| static PlannedStmt *planQuery(char *szSqlText) |
| { |
| Assert(szSqlText); |
| Assert(szSqlText); |
| |
| List *plQueryTree = pg_parse_and_rewrite(szSqlText, NULL, 0); |
| |
| if (1 != gpdb::UlListLength(plQueryTree)) |
| { |
| elog(ERROR, "problem parsing query %s", szSqlText); |
| } |
| |
| Query *pqueryTree = (Query *) lfirst(gpdb::PlcListHead(plQueryTree)); |
| |
| PlannedStmt *pplstmt = pg_plan_query(pqueryTree, NULL, QRL_NONE); |
| |
| if (!pplstmt) |
| { |
| elog(ERROR, "problem planned query %s. query tree is %s", szSqlText, gpdb::SzNodeToString(pqueryTree)); |
| } |
| |
| return pplstmt; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // getQueryBinary |
| // |
| // @doc: |
| // This method takes a SQL text, calls the parser and gets a GPDB query object. |
| // Lastly serializes the plan with auxillary structures. |
| // Inputs: |
| // szSqlText - SQL text |
| // Output: |
| // piLength - length of serialized GPDB query object |
| // Return: |
| // serialized GPDB query buffer. |
| // |
| //--------------------------------------------------------------------------- |
| |
| static char *getQueryBinary |
| ( |
| char *szSqlText, |
| size_t *piLength |
| ) |
| { |
| Query *pquery = parseSQL(szSqlText); |
| |
| int iQueryStringLen = -1; |
| char *pcQuery = nodeToBinaryStringFast((Node *) pquery, &iQueryStringLen); |
| |
| Assert(pcQuery); |
| |
| // Write all the serialized structures into a single bytea |
| size_t iSerializedStructure = sizeof(ULONG); |
| iSerializedStructure += iQueryStringLen; |
| |
| *piLength = iSerializedStructure; |
| |
| char *pcBuf = (char *) gpdb::GPDBAlloc(iSerializedStructure); |
| char *pcRetBuf = pcBuf; |
| |
| memcpy(pcBuf, &iQueryStringLen, sizeof(ULONG)); |
| pcBuf+=sizeof(ULONG); |
| |
| memcpy(pcBuf, pcQuery, iQueryStringLen); |
| pcBuf+=iQueryStringLen; |
| |
| return pcRetBuf; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // getPlannedStmtBinary |
| // |
| // @doc: |
| // This method takes a SQL text, calls the planner and creates a plan |
| // and then serializes the plan with auxillary structures. |
| // Inputs: |
| // szSqlText - SQL text |
| // Output: |
| // piLength - length of serialized plan |
| // Return: |
| // serialized plan buffer. |
| // |
| //--------------------------------------------------------------------------- |
| |
| static char *getPlannedStmtBinary |
| ( |
| char *szSqlText, |
| size_t *piLength |
| ) |
| { |
| |
| PlannedStmt *pplstmt = planQuery(szSqlText); |
| |
| int iPlannedStmtStringLen = -1; |
| char *szPlannedStmtString = nodeToBinaryStringFast((Node *) pplstmt, &iPlannedStmtStringLen); |
| |
| Assert(szPlannedStmtString); |
| |
| // Write all the serialized structures into a single bytea |
| size_t iSerializedStructure = sizeof(ULONG); |
| iSerializedStructure += iPlannedStmtStringLen; |
| |
| *piLength = iSerializedStructure; |
| |
| char *pcBuf = (char *) gpdb::GPDBAlloc(iSerializedStructure); |
| char *pcRetBuf = pcBuf; |
| |
| memcpy(pcBuf, &iPlannedStmtStringLen, sizeof(ULONG)); |
| pcBuf+=sizeof(ULONG); |
| |
| memcpy(pcBuf, szPlannedStmtString, iPlannedStmtStringLen); |
| pcBuf+=iPlannedStmtStringLen; |
| |
| return pcRetBuf; |
| } |
| |
| static int translateQueryToFile |
| ( |
| char *szSqlText, |
| char *szFilename |
| ) |
| { |
| Query *pquery = parseSQL(szSqlText); |
| |
| Assert(pquery); |
| |
| char *szXmlString = COptTasks::SzDXL(pquery); |
| int iLen = (int) gpos::clib::UlStrLen(szXmlString); |
| |
| CFileWriter fw; |
| fw.Open(szFilename, S_IRUSR | S_IWUSR); |
| fw.Write(reinterpret_cast<const BYTE*>(szXmlString), iLen + 1); |
| fw.Close(); |
| |
| return iLen; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpQuery |
| // |
| // @doc: |
| // Parse a query and dump out query object as a bytea. |
| // Input: sql query text |
| // Output: serialized version of query as bytea |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpQuery(PG_FUNCTION_ARGS) |
| { |
| char *szSqlText = textToString(PG_GETARG_TEXT_P(0)); |
| |
| Query *pquery = parseSQL(szSqlText); |
| elog(NOTICE, "(DumpQuery - Original) \n %s", pretty_format_node_dump(const_cast<char*>(gpdb::SzNodeToString(pquery)))); |
| |
| Query *pqueryNormalized = preprocess_query_optimizer(pquery, NULL); |
| elog(NOTICE, "(DumpQuery - Normalized) \n %s", pretty_format_node_dump(const_cast<char*>(gpdb::SzNodeToString(pqueryNormalized)))); |
| |
| text *ptResult = stringToText("Query dumped"); |
| |
| PG_RETURN_TEXT_P(ptResult); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // RestoreQuery |
| // |
| // @doc: |
| // Restores a query, along with meta-data from a bytea, plans it, and executes it. |
| // Input: bytea corresponding to serialized plan |
| // Output: number of rows corresponding to execution of plan. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| RestoreQuery(PG_FUNCTION_ARGS) |
| { |
| bytea *pbyteaData = PG_GETARG_BYTEA_P(0); |
| |
| char *pcSerializedData = VARDATA(pbyteaData); |
| |
| int iProcessed = extractFrozenQueryPlanAndExecute(pcSerializedData); |
| |
| elog(NOTICE, "(RestorePlan) PROCESSED %d", iProcessed); |
| StringInfoData str; |
| initStringInfo(&str); |
| |
| appendStringInfo(&str, "Query processed %d rows", iProcessed); |
| text *ptResult = stringToText(str.data); |
| |
| PG_RETURN_TEXT_P(ptResult); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpQueryToFile |
| // |
| // @doc: |
| // Parse SQL query, extract meta-data and dump it to a file. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpQueryToFile(PG_FUNCTION_ARGS) |
| { |
| char *szSql = textToString(PG_GETARG_TEXT_P(0)); |
| char *szFilename = textToString(PG_GETARG_TEXT_P(1)); |
| |
| size_t iQueryStringLen = -1; |
| char *pcQuery = getQueryBinary(szSql, &iQueryStringLen); |
| |
| CFileWriter fw; |
| fw.Open(szFilename, S_IRUSR | S_IWUSR); |
| fw.Write(reinterpret_cast<const BYTE*>(&iQueryStringLen), sizeof(iQueryStringLen)); |
| fw.Write(reinterpret_cast<const BYTE*>(pcQuery), iQueryStringLen); |
| fw.Close(); |
| |
| PG_RETURN_UINT32( (ULONG) iQueryStringLen); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpPlanDXL |
| // |
| // @doc: |
| // Plan a query and dump out plan as xml text. |
| // Input: sql query text |
| // Output: plan in dxl |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpPlanDXL(PG_FUNCTION_ARGS) |
| { |
| char *szSqlText = textToString(PG_GETARG_TEXT_P(0)); |
| |
| PlannedStmt *pplstmt = planQuery(szSqlText); |
| |
| Assert(pplstmt); |
| |
| char *szXmlString = COptTasks::SzDXL(pplstmt); |
| if (NULL == szXmlString) |
| { |
| elog(ERROR, "Error translating plan to DXL"); |
| } |
| |
| PG_RETURN_TEXT_P(stringToText(szXmlString)); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpQueryDXL |
| // |
| // @doc: |
| // Parse a query and dump out query as xml text. |
| // Input: sql query text |
| // Output: plan in dxl |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpQueryDXL(PG_FUNCTION_ARGS) |
| { |
| char *szSqlText = textToString(PG_GETARG_TEXT_P(0)); |
| |
| Query *pquery = parseSQL(szSqlText); |
| |
| Assert(pquery); |
| |
| char *szXmlString = COptTasks::SzDXL(pquery); |
| if (NULL == szXmlString) |
| { |
| elog(ERROR, "Error translating query to DXL"); |
| } |
| |
| PG_RETURN_TEXT_P(stringToText(szXmlString)); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpQueryToDXLFile |
| // |
| // @doc: |
| // Parse a query and dump out query as xml text. |
| // Input: sql query text |
| // Output: serialized dxl representation written to file. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpQueryToDXLFile(PG_FUNCTION_ARGS) |
| { |
| char *szSqlText = textToString(PG_GETARG_TEXT_P(0)); |
| char *szFilename = textToString(PG_GETARG_TEXT_P(1)); |
| |
| int iLen = translateQueryToFile(szSqlText, szFilename); |
| |
| PG_RETURN_INT32(iLen); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpQueryFromFileToDXLFile |
| // |
| // @doc: |
| // Parse a query and dump out query as xml text. |
| // Input: name of the file containing query |
| // Output: serialized dxl representation written to file. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpQueryFromFileToDXLFile(PG_FUNCTION_ARGS) |
| { |
| char *szSqlFilename = textToString(PG_GETARG_TEXT_P(0)); |
| char *szFilename = textToString(PG_GETARG_TEXT_P(1)); |
| |
| CFileReader fr; |
| fr.Open(szSqlFilename); |
| ULLONG ullSize = fr.UllSize(); |
| |
| char *pcBuf = (char*) gpdb::GPDBAlloc(ullSize + 1); |
| fr.UlpRead((BYTE*)pcBuf, ullSize); |
| pcBuf[ullSize] = '\0'; |
| fr.Close(); |
| |
| int iLen = translateQueryToFile(pcBuf, szFilename); |
| |
| gpdb::GPDBFree(pcBuf); |
| |
| PG_RETURN_INT32(iLen); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // RestoreQueryDXL |
| // |
| // @doc: |
| // Take an xml representation of a plan and execute it. Restores a query, |
| // along with meta-data from a bytea, executes it and returns number of rows. |
| // Input: bytea corresponding to serialized query |
| // Output: number of rows corresponding to execution of plan. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| RestoreQueryDXL(PG_FUNCTION_ARGS) |
| { |
| char *szXmlString = textToString(PG_GETARG_TEXT_P(0)); |
| |
| int iProcessed = executeXMLQuery(szXmlString); |
| |
| StringInfoData str; |
| initStringInfo(&str); |
| appendStringInfo(&str, "processed %d rows", iProcessed); |
| |
| text *ptResult = stringToText(str.data); |
| |
| PG_RETURN_TEXT_P(ptResult); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // RestoreQueryFromDXLFile |
| // |
| // @doc: |
| // Restores a query specified in DXL format in an XML file, executes it |
| // and returns number of rows. |
| // Input: bytea corresponding to XML file name |
| // Output: number of rows corresponding to execution of plan. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| RestoreQueryFromDXLFile(PG_FUNCTION_ARGS) |
| { |
| char *szFilename = textToString(PG_GETARG_TEXT_P(0)); |
| |
| CFileReader fr; |
| fr.Open(szFilename); |
| ULLONG ullSize = fr.UllSize(); |
| |
| char *pcBuf = (char*) gpdb::GPDBAlloc(ullSize + 1); |
| fr.UlpRead((BYTE*)pcBuf, ullSize); |
| pcBuf[ullSize] = '\0'; |
| |
| fr.Close(); |
| |
| int iProcessed = executeXMLQuery(pcBuf); |
| |
| elog(NOTICE, "Processed %d rows.", iProcessed); |
| gpdb::GPDBFree(pcBuf); |
| |
| StringInfoData str; |
| initStringInfo(&str); |
| |
| appendStringInfo(&str, "Query processed %d rows", iProcessed); |
| text *ptResult = stringToText(str.data); |
| |
| PG_RETURN_TEXT_P(ptResult); |
| } |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // EvalExprFromDXLFile |
| // |
| // @doc: |
| // Reads a serialized XML representation of a DXL constant scalar expression |
| // from the file path given by its argument. The expression is then evaluated |
| // by the executor and the result is transformed back to DXL and serialized |
| // as a string. |
| // It doesn't check that the expression is actually constant. |
| // |
| //--------------------------------------------------------------------------- |
| extern "C" { |
| Datum |
| EvalExprFromDXLFile(PG_FUNCTION_ARGS) |
| { |
| char *szFileName = textToString(PG_GETARG_TEXT_P(0)); |
| CFileReader fr; |
| fr.Open(szFileName); |
| ULLONG ullSize = fr.UllSize(); |
| char *pcBuf = (char*) gpdb::GPDBAlloc(ullSize + 1); |
| fr.UlpRead((BYTE*)pcBuf, ullSize); |
| fr.Close(); |
| pcBuf[ullSize] = '\0'; |
| |
| char *szResultDXL = COptTasks::SzEvalExprFromXML(pcBuf); |
| gpdb::GPDBFree(pcBuf); |
| |
| if (NULL != szResultDXL) |
| { |
| text *ptResult = stringToText(szResultDXL); |
| gpdb::GPDBFree(szResultDXL); |
| PG_RETURN_TEXT_P(ptResult); |
| } |
| else |
| { |
| // Return a dummy value so the tests can continue |
| PG_RETURN_NULL(); |
| } |
| } |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // OptimizeMinidumpFromFile |
| // |
| // @doc: |
| // Loads a minidump from the given file path, optimizes it and returns |
| // the string serialized representation of the result as DXL |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| OptimizeMinidumpFromFile(PG_FUNCTION_ARGS) |
| { |
| char *szFileName = textToString(PG_GETARG_TEXT_P(0)); |
| char *szResultDXL = COptTasks::SzOptimizeMinidumpFromFile(szFileName); |
| if (NULL != szResultDXL) |
| { |
| text *ptResult = stringToText(szResultDXL); |
| gpdb::GPDBFree(szResultDXL); |
| PG_RETURN_TEXT_P(ptResult); |
| } |
| else |
| { |
| elog(NOTICE, "Execution of UDF 'OptimizeMinidumpFromFile' failed. Consult the LOG for more information."); |
| |
| // return a dummy value |
| PG_RETURN_NULL(); |
| } |
| } |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // ExecuteMinidumpFromFile |
| // |
| // @doc: |
| // Loads a minidump from the given file path, executes it and returns |
| // the number of rows in the result. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| ExecuteMinidumpFromFile(PG_FUNCTION_ARGS) |
| { |
| char *szFileName = textToString(PG_GETARG_TEXT_P(0)); |
| char *szResultDXL = COptTasks::SzOptimizeMinidumpFromFile(szFileName); |
| if (NULL == szResultDXL) |
| { |
| elog(NOTICE, "Execution of UDF 'ExecuteMinidumpFromFile' failed. Consult the LOG for more information."); |
| |
| // return a dummy value |
| PG_RETURN_NULL(); |
| } |
| int iProcessed = executeXMLPlan(szResultDXL); |
| gpdb::GPDBFree(szResultDXL); |
| StringInfoData str; |
| initStringInfo(&str); |
| appendStringInfo(&str, "processed %d rows", iProcessed); |
| text *ptResult = stringToText(str.data); |
| |
| PG_RETURN_TEXT_P(ptResult); |
| } |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // RestorePlanDXL |
| // |
| // @doc: |
| // Take an xml representation of a plan and execute it. Restores a plan, |
| // along with meta-data from a bytea, executes it and returns number of rows. |
| // Input: bytea corresponding to serialized plan |
| // Output: number of rows corresponding to execution of plan. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| RestorePlanDXL(PG_FUNCTION_ARGS) |
| { |
| char *szXmlString = textToString(PG_GETARG_TEXT_P(0)); |
| |
| int iProcessed = executeXMLPlan(szXmlString); |
| |
| StringInfoData str; |
| initStringInfo(&str); |
| appendStringInfo(&str, "processed %d rows", iProcessed); |
| |
| text *ptResult = stringToText(str.data); |
| |
| PG_RETURN_TEXT_P(ptResult); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // RestorePlanFromDXLFile |
| // |
| // @doc: |
| // Restores a plan specified in DXL format in an XML file, executes it |
| // and returns number of rows. |
| // Input: bytea corresponding to XML file name |
| // Output: number of rows corresponding to execution of plan. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| RestorePlanFromDXLFile(PG_FUNCTION_ARGS) |
| { |
| char *szFilename = textToString(PG_GETARG_TEXT_P(0)); |
| |
| CFileReader fr; |
| fr.Open(szFilename); |
| ULLONG ullSize = fr.UllSize(); |
| |
| char *pcBuf = (char*) gpdb::GPDBAlloc(ullSize + 1); |
| fr.UlpRead((BYTE*)pcBuf, ullSize); |
| pcBuf[ullSize] = '\0'; |
| |
| fr.Close(); |
| |
| int iProcessed = executeXMLPlan(pcBuf); |
| |
| elog(NOTICE, "Processed %d rows.", iProcessed); |
| gpdb::GPDBFree(pcBuf); |
| |
| StringInfoData str; |
| initStringInfo(&str); |
| |
| appendStringInfo(&str, "Query processed %d rows", iProcessed); |
| text *ptResult = stringToText(str.data); |
| |
| PG_RETURN_TEXT_P(ptResult); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpPlanToDXLFile |
| // |
| // @doc: |
| // |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpPlanToDXLFile(PG_FUNCTION_ARGS) |
| { |
| char *szSql = textToString(PG_GETARG_TEXT_P(0)); |
| char *szFilename = textToString(PG_GETARG_TEXT_P(1)); |
| |
| PlannedStmt *pplstmt = planQuery(szSql); |
| Assert(pplstmt); |
| |
| char *szXmlString = COptTasks::SzDXL(pplstmt); |
| |
| int iLen = (int) gpos::clib::UlStrLen(szXmlString); |
| |
| CFileWriter fw; |
| fw.Open(szFilename, S_IRUSR | S_IWUSR); |
| fw.Write(reinterpret_cast<const BYTE*>(szXmlString), iLen + 1); |
| fw.Close(); |
| |
| PG_RETURN_INT32(iLen); |
| |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpMDObjDXL |
| // |
| // @doc: |
| // Dump relcache info about a catalog object |
| // Input: type oid |
| // Output: cache type object into dxl |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpMDObjDXL(PG_FUNCTION_ARGS) |
| { |
| Oid oid = gpdb::OidFromDatum(PG_GETARG_DATUM(0)); |
| |
| char *szDXL = COptTasks::SzMDObjs(ListMake1Oid(oid)); |
| |
| if (NULL == szDXL) |
| { |
| elog(ERROR, "Error dumping MD object"); |
| } |
| |
| PG_RETURN_TEXT_P(stringToText(szDXL)); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpRelStatsDXL |
| // |
| // @doc: |
| // Dump statistics info about a relation |
| // Input: relation oid |
| // Output: relstats object in DXL form |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpRelStatsDXL(PG_FUNCTION_ARGS) |
| { |
| Oid oid = gpdb::OidFromDatum(PG_GETARG_DATUM(0)); |
| |
| char *szDXL = COptTasks::SzRelStats(ListMake1Oid(oid)); |
| |
| PG_RETURN_TEXT_P(stringToText(szDXL)); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpMDCastDXL |
| // |
| // @doc: |
| // Dump cast function between two types |
| // Input: source and destination type oids |
| // Output: scalar cast function in DXL format |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpMDCastDXL(PG_FUNCTION_ARGS) |
| { |
| Oid oidSrc = gpdb::OidFromDatum(PG_GETARG_DATUM(0)); |
| Oid oidDest = gpdb::OidFromDatum(PG_GETARG_DATUM(1)); |
| |
| char *szDXL = COptTasks::SzMDCast(ListMake2Oid(oidSrc, oidDest)); |
| |
| PG_RETURN_TEXT_P(stringToText(szDXL)); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpMDScCmpDXL |
| // |
| // @doc: |
| // Dump scalar comparison operator between two types |
| // Input: left and right type oids and comparison type |
| // Output: scalar comparison object in DXL format |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpMDScCmpDXL(PG_FUNCTION_ARGS) |
| { |
| Oid oidLeft = gpdb::OidFromDatum(PG_GETARG_DATUM(0)); |
| Oid oidRight = gpdb::OidFromDatum(PG_GETARG_DATUM(1)); |
| char *szCmpType = textToString(PG_GETARG_TEXT_P(2)); |
| |
| char *szDXL = COptTasks::SzMDScCmp(ListMake2Oid(oidLeft, oidRight), szCmpType); |
| |
| PG_RETURN_TEXT_P(stringToText(szDXL)); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpCatalogDXL |
| // |
| // @doc: |
| // Dump entire catalog into a DXL file (entire means the objects |
| // supported by MD cache). Returns number of bytes written. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpCatalogDXL(PG_FUNCTION_ARGS) |
| { |
| char *szFilename = textToString(PG_GETARG_TEXT_P(0)); |
| List *plAllOids = CCatalogUtils::PlAllOids(); |
| |
| COptTasks::DumpMDObjs(plAllOids, szFilename); |
| |
| PG_RETURN_INT32(0); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // extractFrozenQueryPlanAndExecute |
| // |
| // @doc: |
| // This method takes a frozen query, thaws it, plans it and executes the |
| // generated plan. |
| // |
| //--------------------------------------------------------------------------- |
| |
| static int extractFrozenQueryPlanAndExecute(char *pcQuery) |
| { |
| Assert(pcQuery); |
| |
| ULONG ulQueryLen = -1; |
| memcpy(&ulQueryLen, pcQuery, sizeof(ULONG)); |
| pcQuery+=sizeof(ULONG); |
| |
| Query *pquery = (Query *) readNodeFromBinaryString(pcQuery, ulQueryLen); |
| |
| pcQuery+=ulQueryLen; |
| |
| PlannedStmt *pplstmt = pg_plan_query(pquery, NULL, QRL_ONCE); |
| |
| if (!pplstmt) |
| { |
| elog(ERROR, "Problem with planned statement of query tree %s", gpdb::SzNodeToString(pquery)); |
| } |
| |
| // The following steps are required to be able to execute the query. |
| |
| DestReceiver *pdest = CreateDestReceiver(DestNone, NULL); |
| QueryDesc *pqueryDesc = CreateQueryDesc(pplstmt, PStrDup("Internal Query") /*plan->query */, |
| ActiveSnapshot, |
| InvalidSnapshot, |
| pdest, |
| NULL /*paramLI*/, |
| false); |
| |
| elog(NOTICE, "Executing thawed plan..."); |
| |
| ExecutorStart(pqueryDesc, 0); |
| |
| ExecutorRun(pqueryDesc, ForwardScanDirection, 0); |
| |
| ExecutorEnd(pqueryDesc); |
| |
| int iProcessed = (int) pqueryDesc->es_processed; |
| |
| FreeQueryDesc(pqueryDesc); |
| |
| return iProcessed; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // extractFrozenPlanAndExecute |
| // |
| // @doc: |
| // This method takes a frozen plan, thaws it and executes the plan. |
| // |
| //--------------------------------------------------------------------------- |
| |
| static int extractFrozenPlanAndExecute(char *pcSerializedPS) |
| { |
| Assert(pcSerializedPS); |
| |
| ULONG ulPlannedStmtLen = -1; |
| memcpy(&ulPlannedStmtLen, pcSerializedPS, sizeof(ULONG)); |
| pcSerializedPS+=sizeof(ULONG); |
| |
| PlannedStmt *pplstmt = (PlannedStmt *) readNodeFromBinaryString(pcSerializedPS, ulPlannedStmtLen); |
| |
| pcSerializedPS+=ulPlannedStmtLen; |
| |
| //The following steps are required to be able to execute the query. |
| |
| DestReceiver *pdest = CreateDestReceiver(DestNone, NULL); |
| QueryDesc *pqueryDesc = CreateQueryDesc(pplstmt, PStrDup("Internal Query") /*plan->query */, |
| ActiveSnapshot, |
| InvalidSnapshot, |
| pdest, |
| NULL /*paramLI*/, |
| false); |
| |
| elog(NOTICE, "Executing thawed plan..."); |
| |
| ExecutorStart(pqueryDesc, 0); |
| |
| ExecutorRun(pqueryDesc, ForwardScanDirection, 0); |
| |
| ExecutorEnd(pqueryDesc); |
| |
| int iProcessed = (int) pqueryDesc->es_processed; |
| |
| FreeQueryDesc(pqueryDesc); |
| |
| return iProcessed; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // executeXMLQuery |
| // |
| // @doc: |
| // |
| // |
| //--------------------------------------------------------------------------- |
| |
| static int executeXMLQuery(char *szXml) |
| { |
| Query *pquery = COptTasks::PqueryFromXML(szXml); |
| |
| PlannedStmt *pplstmt = pg_plan_query(pquery, NULL, QRL_ONCE); |
| |
| DestReceiver *pdest = CreateDestReceiver(DestNone, NULL); |
| QueryDesc *pqueryDesc = CreateQueryDesc(pplstmt, PStrDup("Internal Query") /*plan->query */, |
| ActiveSnapshot, |
| InvalidSnapshot, |
| pdest, |
| NULL /*paramLI*/, |
| false); |
| |
| elog(NOTICE, "Executing thawed plan..."); |
| |
| ExecutorStart(pqueryDesc, 0); |
| |
| ExecutorRun(pqueryDesc, ForwardScanDirection, 0); |
| |
| ExecutorEnd(pqueryDesc); |
| |
| int iProcessed = (int) pqueryDesc->es_processed; |
| |
| FreeQueryDesc(pqueryDesc); |
| |
| return iProcessed; |
| } |
| |
| static int executeXMLPlan(char *szXml) |
| { |
| PlannedStmt *pplstmt = COptTasks::PplstmtFromXML(szXml); |
| |
| // The following steps are required to be able to execute the query. |
| |
| DestReceiver *pdest = CreateDestReceiver(DestNone, NULL); |
| QueryDesc *pqueryDesc = CreateQueryDesc(pplstmt, PStrDup("Internal Query") /*plan->query */, |
| ActiveSnapshot, |
| InvalidSnapshot, |
| pdest, |
| NULL /*paramLI*/, |
| false); |
| |
| elog(NOTICE, "Executing thawed plan..."); |
| |
| ExecutorStart(pqueryDesc, 0); |
| |
| ExecutorRun(pqueryDesc, ForwardScanDirection, 0); |
| |
| ExecutorEnd(pqueryDesc); |
| |
| int iProcessed = (int) pqueryDesc->es_processed; |
| |
| FreeQueryDesc(pqueryDesc); |
| |
| return iProcessed; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // RestoreQueryFromFile |
| // |
| // @doc: |
| // Restores a query, along with meta-data from a bytea, plans the query |
| // executes it and returns number of rows. |
| // Input: bytea corresponding to serialized query along with auxillary information |
| // Output: number of rows corresponding to execution of plan. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| RestoreQueryFromFile(PG_FUNCTION_ARGS) |
| { |
| char *szFilename = textToString(PG_GETARG_TEXT_P(0)); |
| |
| CFileReader fr; |
| fr.Open(szFilename); |
| ULLONG ullSize = fr.UllSize(); |
| elog(NOTICE, "(RestoreFromFile) Filesize is %d", ullSize); |
| |
| char *pcBuf = (char*) gpdb::GPDBAlloc(ullSize); |
| fr.UlpRead((BYTE*)pcBuf, ullSize); |
| fr.Close(); |
| |
| int iBinaryLen; |
| memcpy(&iBinaryLen, pcBuf, sizeof(int)); |
| Assert(iBinaryLen == ullSize - sizeof(int)); |
| |
| elog(NOTICE, "(RestoreFromFile) BinaryLen is %d", iBinaryLen); |
| char *pcBinary = pcBuf + sizeof(int); |
| |
| int iProcessed = extractFrozenQueryPlanAndExecute(pcBinary); |
| |
| elog(NOTICE, "(RestorePlan) PROCESSED %d", iProcessed); |
| StringInfoData str; |
| initStringInfo(&str); |
| |
| appendStringInfo(&str, "Query processed %d rows", iProcessed); |
| text *ptResult = stringToText(str.data); |
| |
| PG_RETURN_TEXT_P(ptResult); |
| } |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DisableXform |
| // |
| // @doc: |
| // Takes transformation name as input, and disables this transformation. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DisableXform(PG_FUNCTION_ARGS) |
| { |
| char *szXform = textToString(PG_GETARG_TEXT_P(0)); |
| bool fResult = COptTasks::FSetXform(szXform, true /*fDisable*/); |
| |
| StringInfoData str; |
| initStringInfo(&str); |
| |
| if (fResult) |
| { |
| appendStringInfo(&str, "%s is disabled", szXform); |
| } |
| else |
| { |
| appendStringInfo(&str, "%s is not recognized", szXform); |
| } |
| text *result = stringToText(str.data); |
| |
| PG_RETURN_TEXT_P(result); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // EnableXform |
| // |
| // @doc: |
| // Takes transformation name as input, and enables this transformation. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| EnableXform(PG_FUNCTION_ARGS) |
| { |
| char *szXform = textToString(PG_GETARG_TEXT_P(0)); |
| bool fResult = COptTasks::FSetXform(szXform, false /*fDisable*/); |
| |
| StringInfoData str; |
| initStringInfo(&str); |
| |
| if (fResult) |
| { |
| appendStringInfo(&str, "%s is enabled", szXform); |
| } |
| else |
| { |
| appendStringInfo(&str, "%s is not recognized", szXform); |
| } |
| text *result = stringToText(str.data); |
| |
| PG_RETURN_TEXT_P(result); |
| } |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // DumpPlanToFile |
| // |
| // @doc: |
| // Plan SQL query, extract meta-data and dump it to a file. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| DumpPlanToFile(PG_FUNCTION_ARGS) |
| { |
| char *szSql = textToString(PG_GETARG_TEXT_P(0)); |
| char *szFilename = textToString(PG_GETARG_TEXT_P(1)); |
| |
| size_t iBinaryLen = -1; |
| char *pcBinary = getPlannedStmtBinary(szSql, &iBinaryLen); |
| |
| CFileWriter fw; |
| fw.Open(szFilename, S_IRUSR | S_IWUSR); |
| fw.Write(reinterpret_cast<const BYTE*>(&iBinaryLen), sizeof(iBinaryLen)); |
| fw.Write(reinterpret_cast<const BYTE*>(pcBinary), iBinaryLen); |
| fw.Close(); |
| |
| PG_RETURN_UINT32((ULONG) iBinaryLen); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // LibraryVersion |
| // |
| // @doc: |
| // Returns the optimizer and gpos library versions as a message |
| // |
| //--------------------------------------------------------------------------- |
| extern "C" { |
| Datum |
| LibraryVersion() |
| { |
| StringInfoData str; |
| initStringInfo(&str); |
| appendStringInfo(&str, "GPOPT version: %s", GPOPT_VERSION); |
| appendStringInfo(&str, ", GPOS version: %s", GPOS_VERSION); |
| appendStringInfo(&str, ", Xerces version: %s", XERCES_VERSION); |
| text *result = stringToText(str.data); |
| |
| PG_RETURN_TEXT_P(result); |
| } |
| } |
| |
| extern "C" { |
| StringInfo |
| OptVersion() |
| { |
| StringInfo str = gpdb::SiMakeStringInfo(); |
| appendStringInfo(str, "%s", GPOPT_VERSION); |
| |
| return str; |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // RestorePlanFromFile |
| // |
| // @doc: |
| // Restores a plan along with meta data from a file, executes it and |
| // returns number of rows. |
| // Input: bytea corresponding to serialized plan |
| // Output: number of rows corresponding to execution of plan. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| RestorePlanFromFile(PG_FUNCTION_ARGS) |
| { |
| char *szFilename = textToString(PG_GETARG_TEXT_P(0)); |
| |
| CFileReader fr; |
| fr.Open(szFilename); |
| ULLONG ullSize = fr.UllSize(); |
| |
| char *pcBuf = (char*) gpdb::GPDBAlloc(ullSize); |
| fr.UlpRead((BYTE*)pcBuf, ullSize); |
| fr.Close(); |
| |
| int iBinaryLen; |
| memcpy(&iBinaryLen, pcBuf, sizeof(int)); |
| Assert(iBinaryLen == ullSize - sizeof(int)); |
| |
| char *pcBinary = pcBuf + sizeof(int); |
| |
| int iProcessed = extractFrozenPlanAndExecute(pcBinary); |
| |
| elog(NOTICE, "Processed %d rows.", iProcessed); |
| gpdb::GPDBFree(pcBuf); |
| |
| StringInfoData str; |
| initStringInfo(&str); |
| |
| appendStringInfo(&str, "Query processed %d rows", iProcessed); |
| text *ptResult = stringToText(str.data); |
| |
| PG_RETURN_TEXT_P(ptResult); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // Optimize |
| // |
| // @doc: |
| // Optimize the query using the new optimizer |
| // Input: sql query text |
| // Output: number of rows corresponding to execution |
| // of plan generated by the new optimizer. |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| Datum |
| Optimize(PG_FUNCTION_ARGS) |
| { |
| char *szSQLText = textToString(PG_GETARG_TEXT_P(0)); |
| |
| Query *pquery = parseSQL(szSQLText); |
| Query *pqueryNormalized = preprocess_query_optimizer(pquery, NULL); |
| |
| Assert(pqueryNormalized); |
| |
| char *szOutput = COptTasks::SzOptimize(pqueryNormalized); |
| |
| if (NULL == szOutput) |
| { |
| elog(ERROR, "Error optimizing query"); |
| } |
| |
| PG_RETURN_TEXT_P(stringToText(szOutput)); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // @function: |
| // orca |
| // |
| // @doc: |
| // API for planner replacement |
| // |
| //--------------------------------------------------------------------------- |
| |
| extern "C" { |
| PlannedStmt *orca(Query *pquery) |
| { |
| BOOL fUnexpectedFailure = false; |
| |
| return COptTasks::PplstmtOptimize(pquery, &fUnexpectedFailure); |
| } |
| } |
| |
| |
| extern "C" { |
| char *read_file(const char *szFilename) |
| { |
| CFileReader fr; |
| fr.Open(szFilename); |
| ULLONG ullSize = fr.UllSize(); |
| |
| char *pcBuf = (char*) gpdb::GPDBAlloc(ullSize); |
| fr.UlpRead((BYTE*)pcBuf, ullSize); |
| pcBuf[ullSize] = '\0'; |
| |
| fr.Close(); |
| return pcBuf; |
| } |
| } |
| |
| // EOF |