From 7e9396ffa1515d45927f0cde08855e4f4867d777 Mon Sep 17 00:00:00 2001 From: h-serizawa Date: Thu, 24 Mar 2022 16:42:22 +0900 Subject: [PATCH 1/3] ConnectBy supports VARCHAR inputs. --- compatlib_functions/Makefile | 12 +-- compatlib_functions/ddl/install.sql | 4 +- compatlib_functions/src/ConnectBy.cpp | 143 ++++++++++++++++++++------ 3 files changed, 120 insertions(+), 39 deletions(-) diff --git a/compatlib_functions/Makefile b/compatlib_functions/Makefile index 0d5d62a..4d8d6a2 100644 --- a/compatlib_functions/Makefile +++ b/compatlib_functions/Makefile @@ -8,6 +8,7 @@ SDK?=/opt/vertica/sdk VSQL?=vsql +COMPATLIB_DEBUG = 0 VERTICA_SDK_INCLUDE = $(SDK)/include SIMULATOR_PATH = $(SDK)/simulator @@ -23,7 +24,7 @@ BUILD_FILES = build/Vertica.o \ PACKAGE_LIBNAME = lib/CompatLib.so CXX=g++ -CXXFLAGS=-g -D HAVE_LONG_LONG_INT_64 -c -I ../include -Wall -Wno-unused-value -fPIC -I $(VERTICA_SDK_INCLUDE) -I $(THIRD_PARTY_INCLUDE) +CXXFLAGS=-g -DHAVE_LONG_LONG_INT_64 -D_GLIBCXX_USE_CXX11_ABI=0 -DCOMPATLIB_DEBUG=$(COMPATLIB_DEBUG) -c -I ../include -Wall -Wno-unused-value -fPIC -std=c++11 -I $(VERTICA_SDK_INCLUDE) -I $(THIRD_PARTY_INCLUDE) LDFLAGS=-shared # add optimization if not a debug build @@ -37,9 +38,9 @@ endif all: $(PACKAGE_LIBNAME) # Main target that builds the package library -$(PACKAGE_LIBNAME): $(BUILD_FILES) +$(PACKAGE_LIBNAME): $(BUILD_FILES) mkdir -p lib - $(CXX) $(LDFLAGS) -o $@ $(BUILD_FILES) + $(CXX) $(LDFLAGS) -o $@ $(BUILD_FILES) # rule to make build/XXX.so from src/XXX.so build/%.o: src/%.cpp @@ -54,7 +55,7 @@ build/Vertica.o: $(VERTICA_SDK_INCLUDE)/Vertica.cpp # example rule to make build/XX.o from third-party/src/*.c #build/%.o: $(THIRD_PARTY)/src/%.c # @mkdir -p build -# $(CXX) $(CXXFLAGS) $< -o $@ +# $(CXX) $(CXXFLAGS) $< -o $@ # Targets to install and uninstall the library and functions @@ -88,5 +89,4 @@ sim_test: all simulator # build the simulator (in SIMULATOR_PATH) and simlink it here simulator: $(MAKE) -C $(SIMULATOR_PATH) - ln -f -s $(SIMULATOR_PATH)/vsim - + ln -f -s $(SIMULATOR_PATH)/vsim diff --git a/compatlib_functions/ddl/install.sql b/compatlib_functions/ddl/install.sql index b17046b..fc838fb 100644 --- a/compatlib_functions/ddl/install.sql +++ b/compatlib_functions/ddl/install.sql @@ -3,7 +3,8 @@ select version(); \set libfile '\''`pwd`'/lib/CompatLib.so\''; CREATE LIBRARY CompatLib AS :libfile; -CREATE TRANSFORM FUNCTION connect_by_path AS LANGUAGE 'C++' NAME 'ConnectByFactory' LIBRARY CompatLib; +CREATE TRANSFORM FUNCTION connect_by_path AS LANGUAGE 'C++' NAME 'ConnectByIntFactory' LIBRARY CompatLib; +CREATE TRANSFORM FUNCTION connect_by_path AS LANGUAGE 'C++' NAME 'ConnectByVarcharFactory' LIBRARY CompatLib; CREATE TRANSFORM FUNCTION transpose AS LANGUAGE 'C++' NAME 'TransposeFactory' LIBRARY CompatLib; -- Add more as needed @@ -11,4 +12,3 @@ CREATE TRANSFORM FUNCTION group_generator_3 AS LANGUAGE 'C++' NAME 'GroupGenerat CREATE TRANSFORM FUNCTION group_generator_3 AS LANGUAGE 'C++' NAME 'GroupGeneratorFactoryFVF' LIBRARY CompatLib; CREATE TRANSFORM FUNCTION group_generator_4 AS LANGUAGE 'C++' NAME 'GroupGeneratorFactoryVVVV' LIBRARY CompatLib; CREATE TRANSFORM FUNCTION group_generator_4 AS LANGUAGE 'C++' NAME 'GroupGeneratorFactoryFVFV' LIBRARY CompatLib; - diff --git a/compatlib_functions/src/ConnectBy.cpp b/compatlib_functions/src/ConnectBy.cpp index 0a69b4e..ed273d0 100644 --- a/compatlib_functions/src/ConnectBy.cpp +++ b/compatlib_functions/src/ConnectBy.cpp @@ -1,54 +1,67 @@ #include "Vertica.h" -#include +#include #include using namespace Vertica; using namespace std; -const int WIDTH = 2000; +const int WIDTH = 65000; class ConnectBy : public TransformFunction { + BaseDataOID argTypeOID; // data type OID of parent ID and child ID + + virtual void setup(ServerInterface &srvInterface, const SizedColumnTypes &argTypes) + { + // Get data type OID of parent ID and child ID + const VerticaType argType = argTypes.getColumnType(0); + argTypeOID = argType.getTypeOid(); + } + virtual void processPartition(ServerInterface &srvInterface, PartitionReader &input_reader, PartitionWriter &output_writer) { - map parent; - map label; - map separator; - + map parent; + map label; + map separator; if (input_reader.getNumCols() != 4) vt_report_error(0, "Function only accepts 4 argument, but %zu provided", input_reader.getNumCols()); + string childValue = ""; + do { - parent[input_reader.getIntRef(1)] = input_reader.getIntRef(0); - label[input_reader.getIntRef(1)] = input_reader.getStringRef(2).str(); - separator[input_reader.getIntRef(1)] = input_reader.getStringRef(3).str(); + childValue = getArgValueAsString(input_reader, 1); + if (childValue == "") + continue; - std::string inString = input_reader.getStringRef(2).str(); + parent[childValue] = getArgValueAsString(input_reader, 0); + label[childValue] = input_reader.getStringRef(2).str(); + separator[childValue] = input_reader.getStringRef(3).str(); + //std::string inString = input_reader.getStringRef(2).str(); //srvInterface.log(" adding %s ", inString.c_str()); - - } while (input_reader.next()); //srvInterface.log("1"); // exit(0); - map cache; - map depth; - map::iterator p; + map cache; + map depth; + map::iterator p; for (p = label.begin(); p != label.end(); ++p) { if (cache.count(p->first) == 0) { string output = p->second; vint current_depth = 0; - vint current = parent[p->first]; - while (current != 0 ) { + string current = parent[p->first]; + while (current != "") { - srvInterface.log("working on %lld", current); +#if COMPATLIB_DEBUG + srvInterface.log("working on %s", current.c_str()); +#endif if (cache.count(current) > 0 ) { // Found the parent's path in the cache @@ -67,26 +80,57 @@ class ConnectBy : public TransformFunction depth[p->first] = current_depth; } - srvInterface.log("attempting to output %lld", p->first); - - output_writer.setInt(0,p->first); - output_writer.setInt(1,depth[p->first]); +#if COMPATLIB_DEBUG + srvInterface.log("attempting to output %s", p->first.c_str()); +#endif + + switch(argTypeOID) { + case VarcharOID: { + VString &word = output_writer.getStringRef(0); + word.copy(p->first); + break; + } + case Int8OID: + output_writer.setInt(0, stoll(p->first)); + break; + default: + break; + } + output_writer.setInt(1, depth[p->first]); VString &word = output_writer.getStringRef(2); word.copy(cache[p->first]); output_writer.next(); } - } - +private: + string getArgValueAsString(PartitionReader &input_reader, size_t idx) + { + string value = ""; + if (!input_reader.isNull(idx)) { + switch(argTypeOID) { + case VarcharOID: + value = input_reader.getStringRef(idx).str(); + break; + case Int8OID: { + vint intValue = input_reader.getIntRef(idx); + value = to_string(intValue); + break; + } + default: + break; + } + } + return value; + } }; - -class ConnectByFactory : public TransformFunctionFactory +// This factory accepts function calls with integer arguments for parent ID and child ID +class ConnectByIntFactory : public TransformFunctionFactory { - // Tell Vertica that we take in a row with 5 inputs (parent ID, child ID, label, separator, - // and return a row with 2 strings (id, path) + // Tell Vertica that we take in a row with 4 inputs (parent ID, child ID, label, separator) + // and return a row with 3 values (id, depth, path) virtual void getPrototype(ServerInterface &srvInterface, ColumnTypes &argTypes, ColumnTypes &returnType) { argTypes.addInt(); @@ -105,9 +149,9 @@ class ConnectByFactory : public TransformFunctionFactory const SizedColumnTypes &input_types, SizedColumnTypes &output_types) { - // Error out if we're called with anything but 1 argument + // Error out if we're called with anything not 4 arguments if (input_types.getColumnCount() != 4) - vt_report_error(0, "Function only accepts 3 arguments, but %zu provided", input_types.getColumnCount()); + vt_report_error(0, "Function only accepts 4 arguments, but %zu provided", input_types.getColumnCount()); // Our output size will never be more than the input size @@ -121,6 +165,43 @@ class ConnectByFactory : public TransformFunctionFactory }; -RegisterFactory(ConnectByFactory); +RegisterFactory(ConnectByIntFactory); + +// This factory accepts function calls with varchar arguments for parent ID and child ID +class ConnectByVarcharFactory : public TransformFunctionFactory +{ + // Tell Vertica that we take in a row with 4 inputs (parent ID, child ID, label, separator) + // and return a row with 3 values (id, depth, path) + virtual void getPrototype(ServerInterface &srvInterface, ColumnTypes &argTypes, ColumnTypes &returnType) + { + argTypes.addVarchar(); // parent ID + argTypes.addVarchar(); // child ID + argTypes.addVarchar(); // label + argTypes.addVarchar(); // separator + + returnType.addVarchar(); // id + returnType.addInt(); // depth + returnType.addVarchar(); // separator + } + + // Tell Vertica what our return string length will be, given the input string length + virtual void getReturnType(ServerInterface &srvInterface, + const SizedColumnTypes &input_types, + SizedColumnTypes &output_types) + { + // Error out if we're called with anything not 4 arguments + if (input_types.getColumnCount() != 4) + vt_report_error(0, "Function only accepts 4 arguments, but %zu provided", input_types.getColumnCount()); + + output_types.addVarchar(WIDTH, "identifier"); + output_types.addInt("depth"); + output_types.addVarchar(WIDTH, "path"); + } + + virtual TransformFunction *createTransformFunction(ServerInterface &srvInterface) + { return vt_createFuncObj(srvInterface.allocator, ConnectBy); } + +}; +RegisterFactory(ConnectByVarcharFactory); From 0c16f3882466162eb2b3f40f0f2205f71ea401f6 Mon Sep 17 00:00:00 2001 From: h-serizawa Date: Thu, 24 Mar 2022 16:47:50 +0900 Subject: [PATCH 2/3] ConnectBy supports VARCHAR inputs. --- compatlib_functions/Makefile | 12 +- compatlib_functions/ddl/install.sql | 4 +- .../examples/connect_by_path.sql | 2 + compatlib_functions/src/ConnectBy.cpp | 143 ++++++++++++++---- 4 files changed, 122 insertions(+), 39 deletions(-) diff --git a/compatlib_functions/Makefile b/compatlib_functions/Makefile index 0d5d62a..4d8d6a2 100644 --- a/compatlib_functions/Makefile +++ b/compatlib_functions/Makefile @@ -8,6 +8,7 @@ SDK?=/opt/vertica/sdk VSQL?=vsql +COMPATLIB_DEBUG = 0 VERTICA_SDK_INCLUDE = $(SDK)/include SIMULATOR_PATH = $(SDK)/simulator @@ -23,7 +24,7 @@ BUILD_FILES = build/Vertica.o \ PACKAGE_LIBNAME = lib/CompatLib.so CXX=g++ -CXXFLAGS=-g -D HAVE_LONG_LONG_INT_64 -c -I ../include -Wall -Wno-unused-value -fPIC -I $(VERTICA_SDK_INCLUDE) -I $(THIRD_PARTY_INCLUDE) +CXXFLAGS=-g -DHAVE_LONG_LONG_INT_64 -D_GLIBCXX_USE_CXX11_ABI=0 -DCOMPATLIB_DEBUG=$(COMPATLIB_DEBUG) -c -I ../include -Wall -Wno-unused-value -fPIC -std=c++11 -I $(VERTICA_SDK_INCLUDE) -I $(THIRD_PARTY_INCLUDE) LDFLAGS=-shared # add optimization if not a debug build @@ -37,9 +38,9 @@ endif all: $(PACKAGE_LIBNAME) # Main target that builds the package library -$(PACKAGE_LIBNAME): $(BUILD_FILES) +$(PACKAGE_LIBNAME): $(BUILD_FILES) mkdir -p lib - $(CXX) $(LDFLAGS) -o $@ $(BUILD_FILES) + $(CXX) $(LDFLAGS) -o $@ $(BUILD_FILES) # rule to make build/XXX.so from src/XXX.so build/%.o: src/%.cpp @@ -54,7 +55,7 @@ build/Vertica.o: $(VERTICA_SDK_INCLUDE)/Vertica.cpp # example rule to make build/XX.o from third-party/src/*.c #build/%.o: $(THIRD_PARTY)/src/%.c # @mkdir -p build -# $(CXX) $(CXXFLAGS) $< -o $@ +# $(CXX) $(CXXFLAGS) $< -o $@ # Targets to install and uninstall the library and functions @@ -88,5 +89,4 @@ sim_test: all simulator # build the simulator (in SIMULATOR_PATH) and simlink it here simulator: $(MAKE) -C $(SIMULATOR_PATH) - ln -f -s $(SIMULATOR_PATH)/vsim - + ln -f -s $(SIMULATOR_PATH)/vsim diff --git a/compatlib_functions/ddl/install.sql b/compatlib_functions/ddl/install.sql index b17046b..fc838fb 100644 --- a/compatlib_functions/ddl/install.sql +++ b/compatlib_functions/ddl/install.sql @@ -3,7 +3,8 @@ select version(); \set libfile '\''`pwd`'/lib/CompatLib.so\''; CREATE LIBRARY CompatLib AS :libfile; -CREATE TRANSFORM FUNCTION connect_by_path AS LANGUAGE 'C++' NAME 'ConnectByFactory' LIBRARY CompatLib; +CREATE TRANSFORM FUNCTION connect_by_path AS LANGUAGE 'C++' NAME 'ConnectByIntFactory' LIBRARY CompatLib; +CREATE TRANSFORM FUNCTION connect_by_path AS LANGUAGE 'C++' NAME 'ConnectByVarcharFactory' LIBRARY CompatLib; CREATE TRANSFORM FUNCTION transpose AS LANGUAGE 'C++' NAME 'TransposeFactory' LIBRARY CompatLib; -- Add more as needed @@ -11,4 +12,3 @@ CREATE TRANSFORM FUNCTION group_generator_3 AS LANGUAGE 'C++' NAME 'GroupGenerat CREATE TRANSFORM FUNCTION group_generator_3 AS LANGUAGE 'C++' NAME 'GroupGeneratorFactoryFVF' LIBRARY CompatLib; CREATE TRANSFORM FUNCTION group_generator_4 AS LANGUAGE 'C++' NAME 'GroupGeneratorFactoryVVVV' LIBRARY CompatLib; CREATE TRANSFORM FUNCTION group_generator_4 AS LANGUAGE 'C++' NAME 'GroupGeneratorFactoryFVFV' LIBRARY CompatLib; - diff --git a/compatlib_functions/examples/connect_by_path.sql b/compatlib_functions/examples/connect_by_path.sql index 6a5d80b..f8b9feb 100644 --- a/compatlib_functions/examples/connect_by_path.sql +++ b/compatlib_functions/examples/connect_by_path.sql @@ -9,4 +9,6 @@ commit; select connect_by_path(supervisor_id, id, name, ' >> ') over () from company; +select connect_by_path(supervisor_id::VARCHAR, id::VARCHAR, name, ' >> ') over () from company; + drop table company; diff --git a/compatlib_functions/src/ConnectBy.cpp b/compatlib_functions/src/ConnectBy.cpp index 0a69b4e..ed273d0 100644 --- a/compatlib_functions/src/ConnectBy.cpp +++ b/compatlib_functions/src/ConnectBy.cpp @@ -1,54 +1,67 @@ #include "Vertica.h" -#include +#include #include using namespace Vertica; using namespace std; -const int WIDTH = 2000; +const int WIDTH = 65000; class ConnectBy : public TransformFunction { + BaseDataOID argTypeOID; // data type OID of parent ID and child ID + + virtual void setup(ServerInterface &srvInterface, const SizedColumnTypes &argTypes) + { + // Get data type OID of parent ID and child ID + const VerticaType argType = argTypes.getColumnType(0); + argTypeOID = argType.getTypeOid(); + } + virtual void processPartition(ServerInterface &srvInterface, PartitionReader &input_reader, PartitionWriter &output_writer) { - map parent; - map label; - map separator; - + map parent; + map label; + map separator; if (input_reader.getNumCols() != 4) vt_report_error(0, "Function only accepts 4 argument, but %zu provided", input_reader.getNumCols()); + string childValue = ""; + do { - parent[input_reader.getIntRef(1)] = input_reader.getIntRef(0); - label[input_reader.getIntRef(1)] = input_reader.getStringRef(2).str(); - separator[input_reader.getIntRef(1)] = input_reader.getStringRef(3).str(); + childValue = getArgValueAsString(input_reader, 1); + if (childValue == "") + continue; - std::string inString = input_reader.getStringRef(2).str(); + parent[childValue] = getArgValueAsString(input_reader, 0); + label[childValue] = input_reader.getStringRef(2).str(); + separator[childValue] = input_reader.getStringRef(3).str(); + //std::string inString = input_reader.getStringRef(2).str(); //srvInterface.log(" adding %s ", inString.c_str()); - - } while (input_reader.next()); //srvInterface.log("1"); // exit(0); - map cache; - map depth; - map::iterator p; + map cache; + map depth; + map::iterator p; for (p = label.begin(); p != label.end(); ++p) { if (cache.count(p->first) == 0) { string output = p->second; vint current_depth = 0; - vint current = parent[p->first]; - while (current != 0 ) { + string current = parent[p->first]; + while (current != "") { - srvInterface.log("working on %lld", current); +#if COMPATLIB_DEBUG + srvInterface.log("working on %s", current.c_str()); +#endif if (cache.count(current) > 0 ) { // Found the parent's path in the cache @@ -67,26 +80,57 @@ class ConnectBy : public TransformFunction depth[p->first] = current_depth; } - srvInterface.log("attempting to output %lld", p->first); - - output_writer.setInt(0,p->first); - output_writer.setInt(1,depth[p->first]); +#if COMPATLIB_DEBUG + srvInterface.log("attempting to output %s", p->first.c_str()); +#endif + + switch(argTypeOID) { + case VarcharOID: { + VString &word = output_writer.getStringRef(0); + word.copy(p->first); + break; + } + case Int8OID: + output_writer.setInt(0, stoll(p->first)); + break; + default: + break; + } + output_writer.setInt(1, depth[p->first]); VString &word = output_writer.getStringRef(2); word.copy(cache[p->first]); output_writer.next(); } - } - +private: + string getArgValueAsString(PartitionReader &input_reader, size_t idx) + { + string value = ""; + if (!input_reader.isNull(idx)) { + switch(argTypeOID) { + case VarcharOID: + value = input_reader.getStringRef(idx).str(); + break; + case Int8OID: { + vint intValue = input_reader.getIntRef(idx); + value = to_string(intValue); + break; + } + default: + break; + } + } + return value; + } }; - -class ConnectByFactory : public TransformFunctionFactory +// This factory accepts function calls with integer arguments for parent ID and child ID +class ConnectByIntFactory : public TransformFunctionFactory { - // Tell Vertica that we take in a row with 5 inputs (parent ID, child ID, label, separator, - // and return a row with 2 strings (id, path) + // Tell Vertica that we take in a row with 4 inputs (parent ID, child ID, label, separator) + // and return a row with 3 values (id, depth, path) virtual void getPrototype(ServerInterface &srvInterface, ColumnTypes &argTypes, ColumnTypes &returnType) { argTypes.addInt(); @@ -105,9 +149,9 @@ class ConnectByFactory : public TransformFunctionFactory const SizedColumnTypes &input_types, SizedColumnTypes &output_types) { - // Error out if we're called with anything but 1 argument + // Error out if we're called with anything not 4 arguments if (input_types.getColumnCount() != 4) - vt_report_error(0, "Function only accepts 3 arguments, but %zu provided", input_types.getColumnCount()); + vt_report_error(0, "Function only accepts 4 arguments, but %zu provided", input_types.getColumnCount()); // Our output size will never be more than the input size @@ -121,6 +165,43 @@ class ConnectByFactory : public TransformFunctionFactory }; -RegisterFactory(ConnectByFactory); +RegisterFactory(ConnectByIntFactory); + +// This factory accepts function calls with varchar arguments for parent ID and child ID +class ConnectByVarcharFactory : public TransformFunctionFactory +{ + // Tell Vertica that we take in a row with 4 inputs (parent ID, child ID, label, separator) + // and return a row with 3 values (id, depth, path) + virtual void getPrototype(ServerInterface &srvInterface, ColumnTypes &argTypes, ColumnTypes &returnType) + { + argTypes.addVarchar(); // parent ID + argTypes.addVarchar(); // child ID + argTypes.addVarchar(); // label + argTypes.addVarchar(); // separator + + returnType.addVarchar(); // id + returnType.addInt(); // depth + returnType.addVarchar(); // separator + } + + // Tell Vertica what our return string length will be, given the input string length + virtual void getReturnType(ServerInterface &srvInterface, + const SizedColumnTypes &input_types, + SizedColumnTypes &output_types) + { + // Error out if we're called with anything not 4 arguments + if (input_types.getColumnCount() != 4) + vt_report_error(0, "Function only accepts 4 arguments, but %zu provided", input_types.getColumnCount()); + + output_types.addVarchar(WIDTH, "identifier"); + output_types.addInt("depth"); + output_types.addVarchar(WIDTH, "path"); + } + + virtual TransformFunction *createTransformFunction(ServerInterface &srvInterface) + { return vt_createFuncObj(srvInterface.allocator, ConnectBy); } + +}; +RegisterFactory(ConnectByVarcharFactory); From 429bca0101b4e81475e1b9545ddf21dcb167c135 Mon Sep 17 00:00:00 2001 From: h-serizawa Date: Thu, 7 Apr 2022 16:23:28 +0900 Subject: [PATCH 3/3] Solved perf concern by converting int to string --- compatlib_functions/src/ConnectBy.cpp | 159 ++++++++++++++++---------- 1 file changed, 96 insertions(+), 63 deletions(-) diff --git a/compatlib_functions/src/ConnectBy.cpp b/compatlib_functions/src/ConnectBy.cpp index ed273d0..4238514 100644 --- a/compatlib_functions/src/ConnectBy.cpp +++ b/compatlib_functions/src/ConnectBy.cpp @@ -10,8 +10,6 @@ const int WIDTH = 65000; class ConnectBy : public TransformFunction { - BaseDataOID argTypeOID; // data type OID of parent ID and child ID - virtual void setup(ServerInterface &srvInterface, const SizedColumnTypes &argTypes) { // Get data type OID of parent ID and child ID @@ -23,46 +21,112 @@ class ConnectBy : public TransformFunction PartitionReader &input_reader, PartitionWriter &output_writer) { - map parent; - map label; - map separator; - if (input_reader.getNumCols() != 4) vt_report_error(0, "Function only accepts 4 argument, but %zu provided", input_reader.getNumCols()); - string childValue = ""; + switch(argTypeOID) { + case VarcharOID: + internalProcessPartition(srvInterface, input_reader, output_writer); + break; + case Int8OID: + internalProcessPartition(srvInterface, input_reader, output_writer); + break; + default: + break; + } + } + +private: + + BaseDataOID argTypeOID; // data type OID of parent ID and child ID + + bool isEndValue(vint value) + { + return value == vint_null; + } + + bool isEndValue(string value) + { + return value == ""; + } + + void getValueFromReader(vint &output, PartitionReader &input_reader, size_t idx) + { + output = input_reader.getIntRef(idx); + } + + void getValueFromReader(string &output, PartitionReader &input_reader, size_t idx) + { + output = input_reader.getStringRef(idx).str(); + } + + void setValueToWriter(vint value, PartitionWriter &output_writer, size_t idx) + { + output_writer.setInt(idx, value); + } + + void setValueToWriter(string value, PartitionWriter &output_writer, size_t idx) + { + VString &word = output_writer.getStringRef(idx); + word.copy(value); + } + +#if COMPATLIB_DEBUG + void log(ServerInterface &srvInterface, const char *format, string value) + { + srvInterface.log(format, value.c_str()); + } + + void log(ServerInterface &srvInterface, const char *format, vint value) + { + log(srvInterface, format, to_string(value)); + } +#endif + + template + void internalProcessPartition(ServerInterface &srvInterface, + PartitionReader &input_reader, + PartitionWriter &output_writer) + { + map parent; + map label; + map separator; do { - childValue = getArgValueAsString(input_reader, 1); - if (childValue == "") + T childValue; + // If child ID is null, skip it + if (input_reader.isNull(1)) { continue; + } else { + getValueFromReader(childValue, input_reader, 1); + getValueFromReader(parent[childValue], input_reader, 0); + } - parent[childValue] = getArgValueAsString(input_reader, 0); - label[childValue] = input_reader.getStringRef(2).str(); - separator[childValue] = input_reader.getStringRef(3).str(); - - //std::string inString = input_reader.getStringRef(2).str(); - //srvInterface.log(" adding %s ", inString.c_str()); + getValueFromReader(label[childValue], input_reader, 2); + getValueFromReader(separator[childValue], input_reader, 3); } while (input_reader.next()); - //srvInterface.log("1"); - // exit(0); - map cache; - map depth; - map::iterator p; + map cache; + map depth; + typename map::iterator p; for (p = label.begin(); p != label.end(); ++p) { - if (cache.count(p->first) == 0) { +#if COMPATLIB_DEBUG + log(srvInterface, "working on [%s]", p->first); +#endif + + if (cache.count(p->first) == 0) { string output = p->second; - vint current_depth = 0; - string current = parent[p->first]; - while (current != "") { + vint current_depth = 0ull; + T current = parent[p->first]; + #if COMPATLIB_DEBUG - srvInterface.log("working on %s", current.c_str()); + log(srvInterface, " parent: [%s]", current); #endif + while (!isEndValue(current)) { if (cache.count(current) > 0 ) { // Found the parent's path in the cache output = cache[current] + separator[current] + output; @@ -78,52 +142,21 @@ class ConnectBy : public TransformFunction cache[p->first] = output; depth[p->first] = current_depth; - } #if COMPATLIB_DEBUG - srvInterface.log("attempting to output %s", p->first.c_str()); + log(srvInterface, " output: [%s]", output); + log(srvInterface, " depth : [%s]", current_depth); #endif - switch(argTypeOID) { - case VarcharOID: { - VString &word = output_writer.getStringRef(0); - word.copy(p->first); - break; - } - case Int8OID: - output_writer.setInt(0, stoll(p->first)); - break; - default: - break; - } - output_writer.setInt(1, depth[p->first]); - VString &word = output_writer.getStringRef(2); - word.copy(cache[p->first]); + } + + setValueToWriter(p->first, output_writer, 0); + setValueToWriter(depth[p->first], output_writer, 1); + setValueToWriter(cache[p->first], output_writer, 2); output_writer.next(); } } - -private: - string getArgValueAsString(PartitionReader &input_reader, size_t idx) - { - string value = ""; - if (!input_reader.isNull(idx)) { - switch(argTypeOID) { - case VarcharOID: - value = input_reader.getStringRef(idx).str(); - break; - case Int8OID: { - vint intValue = input_reader.getIntRef(idx); - value = to_string(intValue); - break; - } - default: - break; - } - } - return value; - } }; // This factory accepts function calls with integer arguments for parent ID and child ID