Bladeren bron

HPCC-15612 Code Review changes

- Searches for libcouchbase in externals folder
- Splits out class declarations and implementations
- Declares several static methods

Signed-off-by: rpastrana <rodrigo.pastrana@lexisnexis.com>
rpastrana 8 jaren geleden
bovenliggende
commit
1873ff8e2d
3 gewijzigde bestanden met toevoegingen van 804 en 756 verwijderingen
  1. 4 5
      cmake_modules/FindCOUCHBASE.cmake
  2. 560 570
      plugins/couchbase/couchbaseembed.cpp
  3. 240 181
      plugins/couchbase/couchbaseembed.hpp

+ 4 - 5
cmake_modules/FindCOUCHBASE.cmake

@@ -54,13 +54,12 @@ IF (NOT LIBCOUCHBASE_FOUND)
     )
 
     FIND_LIBRARY(
-      MYSQL_LIBRARIES NAMES ${mysql_lib} PATHS "${EXTERNALS_DIRECTORY}/mysql/${osdir}/lib" "${EXTERNALS_DIRECTORY}/mysql/${osdir}" "${EXTERNALS_DIRECTORY}/mysql/lib"
-      NO_DEFAULT_PATH
-    )
-    FIND_LIBRARY (
-      MYSQL_LIBRARIES NAMES ${mysql_lib_alt} PATHS "${EXTERNALS_DIRECTORY}/mysql/${osdir}/lib" "${EXTERNALS_DIRECTORY}/mysql/${osdir}" "${EXTERNALS_DIRECTORY}/mysql/lib"
+      LIBCOUCHBASE_LIBRARIES
+      NAMES couchbase libcouchbase
+      PATHS "${EXTERNALS_DIRECTORY}/couchbase/${osdir}/lib" "${EXTERNALS_DIRECTORY}/couchbase/${osdir}" "${EXTERNALS_DIRECTORY}/couchbase/lib" "${EXTERNALS_DIRECTORY}/libcouchbase/lib" "${EXTERNALS_DIRECTORY}/libcouchbase/${osdir}/lib"
       NO_DEFAULT_PATH
     )
+
   ENDIF()
 
   FIND_PATH (

File diff suppressed because it is too large
+ 560 - 570
plugins/couchbase/couchbaseembed.cpp


+ 240 - 181
plugins/couchbase/couchbaseembed.hpp

@@ -79,7 +79,7 @@ namespace couchbaseembed
         return count;
     }
 
-    void handleDeserializeOutcome(DeserializationResult resultcode, const char * targetype, const char * culpritvalue)
+    static void handleDeserializeOutcome(DeserializationResult resultcode, const char * targetype, const char * culpritvalue)
     {
         switch (resultcode)
         {
@@ -109,6 +109,67 @@ namespace couchbaseembed
         }
     }
 
+    static const char * findUnquotedChar(const char *query, char searchFor)
+    {
+        // Note - returns pointer to char AFTER the first occurrence of searchFor outside of quotes
+        char inStr = '\0';
+        char ch;
+        while ((ch = *query++) != 0)
+        {
+            if (ch == inStr)
+                inStr = false;
+            else switch (ch)
+            {
+            case '\'':
+            case '"':
+                inStr = ch;
+                break;
+            case '\\':
+                if (inStr && *query)
+                    query++;
+                break;
+            case '/':
+                if (!inStr)
+                {
+                    if (*query=='/')
+                    {
+                        while (*query && *query != '\n')
+                            query++;
+                    }
+                    else if (*query=='*')
+                    {
+                        query++;
+                        loop
+                        {
+                            if (!*query)
+                                fail("Unterminated comment in query string");
+                            if (*query=='*' && query[1]=='/')
+                            {
+                                query+= 2;
+                                break;
+                            }
+                            query++;
+                        }
+                    }
+                }
+                break;
+            default:
+                if (!inStr && ch==searchFor)
+                    return query;
+                break;
+            }
+        }
+        return NULL;
+    }
+
+    static unsigned countParameterPlaceholders(const char *query)
+    {
+        unsigned queryCount = 0;
+        while ((query = findUnquotedChar(query, '$')) != NULL)
+            queryCount++;
+        return queryCount;
+    }
+
     class CouchbaseRowStream : public RtlCInterface, implements IRowStream
     {
     public:
@@ -168,223 +229,221 @@ namespace couchbaseembed
             m_oResultRow.set(resultrow);
         }
 
-        virtual bool getBooleanResult(const RtlFieldInfo *field)
+        virtual bool getBooleanResult(const RtlFieldInfo *field);
+        virtual void getDataResult(const RtlFieldInfo *field, size32_t &len, void * &result);
+        virtual double getRealResult(const RtlFieldInfo *field);
+        virtual __int64 getSignedResult(const RtlFieldInfo *field);
+        virtual unsigned __int64 getUnsignedResult(const RtlFieldInfo *field);
+        virtual void getStringResult(const RtlFieldInfo *field, size32_t &chars, char * &result);
+        virtual void getUTF8Result(const RtlFieldInfo *field, size32_t &chars, char * &result);
+        virtual void getUnicodeResult(const RtlFieldInfo *field, size32_t &chars, UChar * &result);
+        virtual void getDecimalResult(const RtlFieldInfo *field, Decimal &value);
+        virtual void processBeginSet(const RtlFieldInfo * field, bool &isAll)
         {
-            const char * value = nextField(field);
-
-            if (!value && !*value)
-            {
-                NullFieldProcessor p(field);
-                return p.boolResult;
-            }
-
-            bool mybool;
-            couchbaseembed::handleDeserializeOutcome(m_tokenDeserializer.deserialize(value, mybool), "bool", value);
-            return mybool;
+            UNSUPPORTED("Embedded Couchbase support error: processBeginSet() not supported");
         }
-
-        virtual void getDataResult(const RtlFieldInfo *field, size32_t &len, void * &result)
+        virtual bool processNextSet(const RtlFieldInfo * field)
         {
-            const char * value = nextField(field);
-
-            if (!value || !*value)
-            {
-                NullFieldProcessor p(field);
-                rtlStrToDataX(len, result, p.resultChars, p.stringResult);
-                return;
-            }
-            rtlStrToDataX(len, result, strlen(value), value);   // This feels like it may not work to me - will preallocate rather larger than we want
+            UNSUPPORTED("Embedded Couchbase support error: processNextSet() not supported");
+            return false;
         }
-
-        virtual double getRealResult(const RtlFieldInfo *field)
+        virtual void processBeginDataset(const RtlFieldInfo * field);
+        virtual void processBeginRow(const RtlFieldInfo * field);
+        virtual bool processNextRow(const RtlFieldInfo * field);
+        virtual void processEndSet(const RtlFieldInfo * field)
         {
-            const char * value = nextField(field);
-
-            if (!value || !*value)
-            {
-                NullFieldProcessor p(field);
-                return p.doubleResult;
-            }
-
-            double mydouble;
-            couchbaseembed::handleDeserializeOutcome(m_tokenDeserializer.deserialize(value, mydouble), "real", value);
-            return mydouble;
+            UNSUPPORTED("Embedded Couchbase support error: processEndSet() not supported");
         }
+        virtual void processEndDataset(const RtlFieldInfo * field);
+        virtual void processEndRow(const RtlFieldInfo * field);
 
-        virtual __int64 getSignedResult(const RtlFieldInfo *field)
-        {
-            const char * value = nextField(field);
-            if (!value || !*value)
-            {
-                NullFieldProcessor p(field);
-                return p.uintResult;
-            }
-
-            __int64 myint64;
-            couchbaseembed::handleDeserializeOutcome(m_tokenDeserializer.deserialize(value, myint64), "signed", value);
-            return myint64;
-        }
+    protected:
+        const char * nextField(const RtlFieldInfo * field);
+    private:
+        TokenDeserializer m_tokenDeserializer;
+        Owned<IPropertyTree> m_oResultRow;
+        Owned<IPropertyTree> m_oNestedField;
+        int m_fieldsProcessedCount;
+        int m_rowFieldCount;
+    };
 
-        virtual unsigned __int64 getUnsignedResult(const RtlFieldInfo *field)
+    // Bind Couchbase columns from an ECL record
+    class CouchbaseRecordBinder : public CInterfaceOf<IFieldProcessor>
+    {
+    public:
+        CouchbaseRecordBinder(const IContextLogger &_logctx, const RtlTypeInfo *_typeInfo, Couchbase::QueryCommand * _pQcmd, int _firstParam)
+         : logctx(_logctx), typeInfo(_typeInfo), m_pQcmd(_pQcmd), firstParam(_firstParam), dummyField("<row>", NULL, typeInfo), thisParam(_firstParam) {}
+
+        int numFields();
+        void processRow(const byte *row);
+        virtual void processString(unsigned len, const char *value, const RtlFieldInfo * field);
+        virtual void processBool(bool value, const RtlFieldInfo * field);
+        virtual void processData(unsigned len, const void *value, const RtlFieldInfo * field);
+        virtual void processInt(__int64 value, const RtlFieldInfo * field);
+        virtual void processUInt(unsigned __int64 value, const RtlFieldInfo * field);
+        virtual void processReal(double value, const RtlFieldInfo * field);
+        virtual void processDecimal(const void *value, unsigned digits, unsigned precision, const RtlFieldInfo * field);
+        virtual void processUDecimal(const void *value, unsigned digits, unsigned precision, const RtlFieldInfo * field)
         {
-            const char * value = nextField(field);
-            if (!value || !*value)
-            {
-                NullFieldProcessor p(field);
-                return p.uintResult;
-            }
-
-            unsigned __int64 myuint64;
-            couchbaseembed::handleDeserializeOutcome(m_tokenDeserializer.deserialize(value, myuint64), "unsigned", value);
-            return myuint64;
+            UNSUPPORTED("UNSIGNED decimals");
         }
 
-        virtual void getStringResult(const RtlFieldInfo *field, size32_t &chars, char * &result)
+        virtual void processUnicode(unsigned chars, const UChar *value, const RtlFieldInfo * field);
+        virtual void processQString(unsigned len, const char *value, const RtlFieldInfo * field);
+        virtual void processUtf8(unsigned chars, const char *value, const RtlFieldInfo * field);
+        virtual bool processBeginSet(const RtlFieldInfo * field, unsigned numElements, bool isAll, const byte *data)
         {
-             const char * value = nextField(field);
-
-            if (!value || !*value)
-            {
-                NullFieldProcessor p(field);
-                rtlStrToStrX(chars, result, p.resultChars, p.stringResult);
-                return;
-            }
-
-            unsigned numchars = rtlUtf8Length(strlen(value), value);  // MORE - is it a good assumption that it is utf8 ? Depends how the database is configured I think
-            rtlUtf8ToStrX(chars, result, numchars, value);
-            return;
+            UNSUPPORTED("SET");
+            return false;
         }
-
-        virtual void getUTF8Result(const RtlFieldInfo *field, size32_t &chars, char * &result)
+        virtual bool processBeginDataset(const RtlFieldInfo * field, unsigned numRows)
         {
-            getStringResult(field, chars, result);
-            return;
+            return false;
         }
-
-        virtual void getUnicodeResult(const RtlFieldInfo *field, size32_t &chars, UChar * &result)
+        virtual bool processBeginRow(const RtlFieldInfo * field)
         {
-            const char * value = nextField(field);
-
-            if (!value || !*value)
-            {
-                NullFieldProcessor p(field);
-                rtlUnicodeToUnicodeX(chars, result, p.resultChars, p.unicodeResult);
-                return;
-            }
-
-            unsigned numchars = rtlUtf8Length(strlen(value), value);  // MORE - is it a good assumption that it is utf8 ? Depends how the database is configured I think
-            rtlUtf8ToUnicodeX(chars, result, numchars, value);
-            return;
+            return true;
         }
-
-        virtual void getDecimalResult(const RtlFieldInfo *field, Decimal &value)
+        virtual void processEndSet(const RtlFieldInfo * field)
         {
-            const char * dvalue = nextField(field);
-            if (!dvalue || !*dvalue)
-            {
-                NullFieldProcessor p(field);
-                value.set(p.decimalResult);
-                return;
-            }
-
-            size32_t chars;
-            rtlDataAttr result;
-            value.setString(strlen(dvalue), dvalue);
-            if (field)
-            {
-                RtlDecimalTypeInfo *dtype = (RtlDecimalTypeInfo *) field->type;
-                value.setPrecision(dtype->getDecimalDigits(), dtype->getDecimalPrecision());
-            }
+            UNSUPPORTED("SET");
         }
-
-        virtual void processBeginSet(const RtlFieldInfo * field, bool &isAll)
+        virtual void processEndDataset(const RtlFieldInfo * field)
         {
-            UNSUPPORTED("Embedded Couchbase support error: processBeginSet() not supported");
+            UNSUPPORTED("DATASET");
         }
-
-        virtual bool processNextSet(const RtlFieldInfo * field)
+        virtual void processEndRow(const RtlFieldInfo * field)
         {
-            UNSUPPORTED("Embedded Couchbase support error: processNextSet() not supported");
-            return false;
         }
 
-        virtual void processBeginDataset(const RtlFieldInfo * field)
-        {
-            /*
-             *
-             *childRec := RECORD real x; real y; END;
-             *parentRec := RECORD
-             * childRec child1,                        <-- flatens out the childrec, this function would receive a field of name x
-             * dataset(childRec) child2;               <-- keeps nested structure, this funciton would receive a field of name child2
-             *END;
-            */
-
-            if (getNumFields(field->type->queryChildType()) > 0)
-                m_oNestedField.set(m_oResultRow->queryBranch(field->name->queryStr()));
-        }
+    protected:
+        inline unsigned checkNextParam(const RtlFieldInfo * field);
+
+        const RtlTypeInfo *typeInfo;
+        Couchbase::QueryCommand * m_pQcmd;
+        const IContextLogger &logctx;
+        int firstParam;
+        RtlFieldStrInfo dummyField;
+        int thisParam;
+        TokenSerializer m_tokenSerializer;
+    };
 
-        virtual void processBeginRow(const RtlFieldInfo * field)
+    class CouchbaseDatasetBinder : public CouchbaseRecordBinder
+    {
+    public:
+        CouchbaseDatasetBinder(const IContextLogger &_logctx, IRowStream * _input, const RtlTypeInfo *_typeInfo, Couchbase::QueryCommand * _pQcmd, int _firstParam)
+          : input(_input), CouchbaseRecordBinder(_logctx, _typeInfo, _pQcmd, _firstParam)
         {
-            m_fieldsProcessedCount = 0;
-            m_rowFieldCount = getNumFields(field->type);
         }
 
-        virtual bool processNextRow(const RtlFieldInfo * field)
+        bool bindNext()
         {
-            return m_fieldsProcessedCount + 1 == m_rowFieldCount;;
+            roxiemem::OwnedConstRoxieRow nextRow = (const byte *) input->ungroupedNextRow();
+            if (!nextRow)
+                return false;
+            processRow((const byte *) nextRow.get());   // Bind the variables for the current row
+            return true;
         }
 
-        virtual void processEndSet(const RtlFieldInfo * field)
+        void executeAll(CouchbaseConnection * conn)
         {
-            UNSUPPORTED("Embedded Couchbase support error: processEndSet() not supported");
-        }
+            while (bindNext())
+            {
+                auto m_pQuery = conn->query(m_pQcmd);
 
-        virtual void processEndDataset(const RtlFieldInfo * field)
-        {
-            if(m_oNestedField)
-                m_oNestedField.clear();
-        }
+                if (m_pQuery->meta().status().errcode() != LCB_SUCCESS )//rows.length() == 0)
+                    failx("Query execution error: %s", m_pQuery->meta().body().to_string().c_str());
 
-        virtual void processEndRow(const RtlFieldInfo * field)
-        {
-            if(m_oNestedField)
-                m_oNestedField.clear();
+                //consider parsing json result
+                if (strstr(m_pQuery->meta().body().data(), "\"status\": \"errors\""))
+                    failx("Err: %s", m_pQuery->meta().body().data());
+            }
         }
 
     protected:
-        const char * nextField(const RtlFieldInfo * field)
-        {
-            m_fieldsProcessedCount++;
-            if (!m_oResultRow)
-                failx("Missing result row data");
-
-            const char * fieldname = field->name->queryStr();
-            if (!fieldname || !*fieldname)
-                failx("Missing result column metadata (name)");
-
-            if (!m_oResultRow->hasProp(fieldname))
-            {
-                VStringBuffer nxpath("locationData/%s", fieldname);
-                if (m_oNestedField)
-                {
-                    if (!m_oNestedField->hasProp(fieldname))
-                    {
-                        StringBuffer xml;
-                        toXML(m_oResultRow, xml);
-                        failx("Result row does not contain field: %s: %s", fieldname, xml.str());
-                    }
-
-                    return m_oNestedField->queryProp(fieldname);
-                }
-            }
-            return m_oResultRow->queryProp(fieldname);
-        }
-    private:
-        TokenDeserializer m_tokenDeserializer;
-        Owned<IPropertyTree> m_oResultRow;
-        Owned<IPropertyTree> m_oNestedField;
-        int m_fieldsProcessedCount;
-        int m_rowFieldCount;;
+        Owned<IRowStream> input;
     };
+
+    class CouchbaseEmbedFunctionContext : public CInterfaceOf<IEmbedFunctionContext>
+    {
+       public:
+           CouchbaseEmbedFunctionContext(const IContextLogger &_logctx, const char *options, unsigned _flags);
+           IPropertyTree * nextResultRowTree();
+           IPropertyTreeIterator * nextResultRowIterator();
+           const char * nextResultScalar();
+           virtual bool getBooleanResult();
+           virtual void getDataResult(size32_t &len, void * &result);
+           virtual double getRealResult();
+           virtual __int64 getSignedResult();
+           virtual unsigned __int64 getUnsignedResult();
+           virtual void getStringResult(size32_t &chars, char * &result);
+           virtual void getUTF8Result(size32_t &chars, char * &result);
+           virtual void getUnicodeResult(size32_t &chars, UChar * &result);
+           virtual void getDecimalResult(Decimal &value);
+           virtual void getSetResult(bool & __isAllResult, size32_t & __resultBytes, void * & __result, int elemType, size32_t elemSize)
+           {
+               UNSUPPORTED("SET results");
+           }
+           virtual IRowStream * getDatasetResult(IEngineRowAllocator * _resultAllocator);
+           virtual byte * getRowResult(IEngineRowAllocator * _resultAllocator);
+           virtual size32_t getTransformResult(ARowBuilder & rowBuilder);
+           virtual void bindRowParam(const char *name, IOutputMetaData & metaVal, byte *val);
+           virtual void bindDatasetParam(const char *name, IOutputMetaData & metaVal, IRowStream * val);
+           virtual void bindBooleanParam(const char *name, bool val);
+           virtual void bindDataParam(const char *name, size32_t len, const void *val);
+           virtual void bindFloatParam(const char *name, float val);
+           virtual void bindRealParam(const char *name, double val);
+           virtual void bindSignedSizeParam(const char *name, int size, __int64 val);
+           virtual void bindSignedParam(const char *name, __int64 val);
+           virtual void bindUnsignedSizeParam(const char *name, int size, unsigned __int64 val);
+           virtual void bindUnsignedParam(const char *name, unsigned __int64 val);
+           virtual void bindStringParam(const char *name, size32_t len, const char *val);
+           virtual void bindVStringParam(const char *name, const char *val);
+           virtual void bindUTF8Param(const char *name, size32_t chars, const char *val);
+           virtual void bindUnicodeParam(const char *name, size32_t chars, const UChar *val);
+           virtual void bindSetParam(const char *name, int elemType, size32_t elemSize, bool isAll, size32_t totalBytes, const void *setData)
+           {
+               UNSUPPORTED("SET parameters");
+           }
+           virtual IInterface *bindParamWriter(IInterface *esdl, const char *esdlservice, const char *esdltype, const char *name)
+           {
+               return NULL;
+           }
+           virtual void paramWriterCommit(IInterface *writer)
+           {
+               UNSUPPORTED("paramWriterCommit");
+           }
+           virtual void writeResult(IInterface *esdl, const char *esdlservice, const char *esdltype, IInterface *writer)
+           {
+               UNSUPPORTED("writeResult");
+           }
+           virtual void importFunction(size32_t lenChars, const char *text)
+           {
+               UNSUPPORTED("importFunction");
+           }
+           virtual void compileEmbeddedScript(size32_t chars, const char *script);
+           virtual void callFunction();
+       protected:
+           void execute();
+           unsigned countBindings(const char *query);
+           const char * findUnquoted(const char *query, char searchFor);
+           unsigned checkNextParam(const char *name);
+
+           const IContextLogger &logctx;
+           Owned<CouchbaseConnection>    m_oCBConnection;
+           Couchbase::Client           * m_pCouchbaseClient;
+           Couchbase::Query            * m_pQuery;
+           Couchbase::QueryCommand     * m_pQcmd;
+
+           StringArray m_Rows;
+           int m_NextRow;
+           Owned<CouchbaseDatasetBinder> m_oInputStream;
+           Couchbase::Internal::RowIterator<Couchbase::QueryRow> * cbQueryIterator;
+           TokenDeserializer m_tokenDeserializer;
+           TokenSerializer m_tokenSerializer;
+           unsigned m_nextParam;
+           unsigned m_numParams;
+           unsigned m_scriptFlags;
+       };
 } // couchbaseembed namespace
 #endif