[Libreoffice-commits] .: connectivity/source dbaccess/source

Eike Rathke erack at kemper.freedesktop.org
Fri Sep 2 16:20:34 PDT 2011


 connectivity/source/parse/sqlbison.y               |   66 +++++++++
 dbaccess/source/ui/querydesign/querycontroller.cxx |  148 +++++++++++++++++++++
 2 files changed, 213 insertions(+), 1 deletion(-)

New commits:
commit bc0a497f08d52450fd74c6372c9f6780f6715e40
Author: Jenei Gábor <jengab at elte.hu>
Date:   Wed Aug 31 12:53:26 2011 +0200

    Fixes fdo#36594 Syntax error in SQL on "--" comment (and "//" and "/**/")
    
    The SQL parser implementation does not handle comments.
    Temporarily remove "-- ..." and "// ..." end-of-line comments and "/* ... */"
    inline comments of a query and append comments after recomposition of the
    query.
    
    NOTE: The original comment positions are not preserved, all comments are
          appended to the query!
    
    Based on the original patch further development was done for inline comments
    and preserving comments' line order.

diff --git a/connectivity/source/parse/sqlbison.y b/connectivity/source/parse/sqlbison.y
index d7e7c67..d559c29 100755
--- a/connectivity/source/parse/sqlbison.y
+++ b/connectivity/source/parse/sqlbison.y
@@ -4570,6 +4570,67 @@ void OSQLParser::setParseTree(OSQLParseNode * pNewParseTree)
 	m_pParseTree = pNewParseTree;
 }
 //-----------------------------------------------------------------------------
+
+/** Delete all comments in a query.
+
+    See also getComment()/concatComment() implementation for
+    OQueryController::translateStatement().
+ */
+static ::rtl::OUString delComment( const ::rtl::OUString& rQuery )
+{
+    // First a quick search if there is any "--" or "//" or "/*", if not then the whole 
+    // copying loop is pointless.
+    if (rQuery.indexOfAsciiL( "--", 2, 0) < 0 && rQuery.indexOfAsciiL( "//", 2, 0) < 0 &&
+            rQuery.indexOfAsciiL( "/*", 2, 0) < 0)
+        return rQuery;
+
+    const sal_Unicode* pCopy = rQuery.getStr();
+    sal_Int32 nQueryLen = rQuery.getLength();
+    bool bIsText1  = false;     // "text"
+    bool bIsText2  = false;     // 'text'
+    bool bComment2 = false;     // /* comment */
+    bool bComment  = false;     // -- or // comment
+    ::rtl::OUStringBuffer aBuf(nQueryLen);
+    for (size_t i=0; i < nQueryLen; ++i)
+    {
+        if (bComment2)
+        {
+            if ((i+1) < nQueryLen)
+            {
+                if (pCopy[i]=='*' && pCopy[i+1]=='/')
+                {
+                    bComment2 = false;
+                    ++i;
+                }
+            }
+            else
+            {
+                // comment can't close anymore, actually an error, but..
+            }
+            continue;
+        }
+        if (pCopy[i] == '\n')
+            bComment = false;
+        else if (!bComment)
+        {
+            if (pCopy[i] == '\"' && !bIsText2)
+                bIsText1 = !bIsText1;
+            else if (pCopy[i] == '\'' && !bIsText1)
+                bIsText2 = !bIsText2;
+            if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen)
+            {
+                if ((pCopy[i]=='-' && pCopy[i+1]=='-') || (pCopy[i]=='/' && pCopy[i+1]=='/'))
+                    bComment = true;
+                else if ((pCopy[i]=='/' && pCopy[i+1]=='*'))
+                    bComment2 = true;
+            }
+        }
+        if (!bComment && !bComment2)
+            aBuf.append( &pCopy[i], 1);
+    }
+    return aBuf.makeStringAndClear();
+}
+//-----------------------------------------------------------------------------
 OSQLParseNode* OSQLParser::parseTree(::rtl::OUString& rErrorMessage,
 									 const ::rtl::OUString& rStatement,
 								     sal_Bool bInternational)
@@ -4581,9 +4642,12 @@ OSQLParseNode* OSQLParser::parseTree(::rtl::OUString& rErrorMessage,
 	// must be reset
 	setParser(this);
 
+	// delete comments before parsing
+	::rtl::OUString sTemp = delComment(rStatement);
+
 	// defines how to scan
 	s_pScanner->SetRule(s_pScanner->GetSQLRule()); // initial
-	s_pScanner->prepareScan(rStatement, m_pContext, bInternational);
+	s_pScanner->prepareScan(sTemp, m_pContext, bInternational);
 
 	SQLyylval.pParseNode = NULL;
 	//	SQLyypvt = NULL;
diff --git a/dbaccess/source/ui/querydesign/querycontroller.cxx b/dbaccess/source/ui/querydesign/querycontroller.cxx
index 054c854..e9ce07a 100644
--- a/dbaccess/source/ui/querydesign/querycontroller.cxx
+++ b/dbaccess/source/ui/querydesign/querycontroller.cxx
@@ -94,6 +94,8 @@
 #include <vcl/msgbox.hxx>
 #include <vcl/svapp.hxx>
 #include <osl/mutex.hxx>
+#include <rtl/strbuf.hxx>
+#include <vector>
 
 extern "C" void SAL_CALL createRegistryInfo_OQueryControl()
 {
@@ -1589,6 +1591,149 @@ bool OQueryController::doSaveAsDoc(sal_Bool _bSaveAs)
 
     return bSuccess;
 }
+//-----------------------------------------------------------------------------
+
+namespace {
+struct CommentStrip
+{
+    ::rtl::OUString maComment;
+    bool            mbLastOnLine;
+    CommentStrip( const ::rtl::OUString& rComment, bool bLastOnLine )
+        : maComment( rComment), mbLastOnLine( bLastOnLine) {}
+};
+}
+
+/** Obtain all comments in a query.
+
+    See also delComment() implementation for OSQLParser::parseTree().
+ */
+static ::std::vector< CommentStrip > getComment( const ::rtl::OUString& rQuery )
+{
+    ::std::vector< CommentStrip > aRet;
+    // First a quick search if there is any "--" or "//" or "/*", if not then 
+    // the whole copying loop is pointless.
+    if (rQuery.indexOfAsciiL( "--", 2, 0) < 0 && rQuery.indexOfAsciiL( "//", 2, 0) < 0 &&
+            rQuery.indexOfAsciiL( "/*", 2, 0) < 0)
+        return aRet;
+
+    const sal_Unicode* pCopy = rQuery.getStr();
+    const sal_Int32 nQueryLen = rQuery.getLength();
+    bool bIsText1  = false;     // "text"
+    bool bIsText2  = false;     // 'text'
+    bool bComment2 = false;     // /* comment */
+    bool bComment  = false;     // -- or // comment
+    ::rtl::OUStringBuffer aBuf;
+    for (sal_Int32 i=0; i < nQueryLen; ++i)
+    {
+        if (bComment2)
+        {
+            aBuf.append( &pCopy[i], 1);
+            if ((i+1) < nQueryLen)
+            {
+                if (pCopy[i]=='*' && pCopy[i+1]=='/')
+                {
+                    bComment2 = false;
+                    aBuf.append( &pCopy[++i], 1);
+                    aRet.push_back( CommentStrip( aBuf.makeStringAndClear(), false));
+                }
+            }
+            else
+            {
+                // comment can't close anymore, actually an error, but..
+                aRet.push_back( CommentStrip( aBuf.makeStringAndClear(), false));
+            }
+            continue;
+        }
+        if (pCopy[i] == '\n' || i == nQueryLen-1)
+        {
+            if (bComment)
+            {
+                if (i == nQueryLen-1 && pCopy[i] != '\n')
+                    aBuf.append( &pCopy[i], 1);
+                aRet.push_back( CommentStrip( aBuf.makeStringAndClear(), true));
+                bComment = false;
+            }
+            else if (!aRet.empty())
+                aRet.back().mbLastOnLine = true;
+        }
+        else if (!bComment)
+        {
+            if (pCopy[i] == '\"' && !bIsText2)
+                bIsText1 = !bIsText1;
+            else if (pCopy[i] == '\'' && !bIsText1)
+                bIsText2 = !bIsText2;
+            if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen)
+            {
+                if ((pCopy[i]=='-' && pCopy[i+1]=='-') || (pCopy[i]=='/' && pCopy[i+1]=='/'))
+                    bComment = true;
+                else if ((pCopy[i]=='/' && pCopy[i+1]=='*'))
+                    bComment2 = true;
+            }
+        }
+        if (bComment || bComment2)
+            aBuf.append( &pCopy[i], 1);
+    }
+    return aRet;
+}
+//------------------------------------------------------------------------------
+
+/** Concat/insert comments that were previously obtained with getComment().
+
+    NOTE: The current parser implementation does not preserve newlines, so all 
+    comments are always appended to the entire query, also inline comments 
+    that would need positioning anyway that can't be obtained after 
+    recomposition. This is ugly but at least allows commented queries while 
+    preserving the comments _somehow_.
+ */
+static ::rtl::OUString concatComment( const ::rtl::OUString& rQuery, const ::std::vector< CommentStrip >& rComments )
+{
+    // No comments => return query.
+    if (rComments.empty())
+        return rQuery;
+
+    const sal_Unicode* pBeg = rQuery.getStr();
+    const sal_Int32 nLen = rQuery.getLength();
+    const size_t nComments = rComments.size();
+    // Obtaining the needed size once should be faster than reallocating.
+    // Also add a blank or linefeed for each comment.
+    sal_Int32 nBufSize = nLen + nComments;
+    for (::std::vector< CommentStrip >::const_iterator it( rComments.begin()); it != rComments.end(); ++it)
+        nBufSize += (*it).maComment.getLength();
+    ::rtl::OUStringBuffer aBuf( nBufSize );
+    sal_Int32 nIndBeg = 0;
+    sal_Int32 nIndLF = rQuery.indexOf('\n');
+    size_t i = 0;
+    while (nIndLF >= 0 && i < nComments)
+    {
+        aBuf.append( pBeg + nIndBeg, nIndLF - nIndBeg);
+        do
+        {
+            aBuf.append( rComments[i].maComment);
+        } while (!rComments[i++].mbLastOnLine && i < nComments);
+        aBuf.append( pBeg + nIndLF, 1);     // the LF
+        nIndBeg = nIndLF + 1;
+        nIndLF = (nIndBeg < nLen ? rQuery.indexOf( '\n', nIndBeg) : -1);
+    }
+    // Append remainder of query.
+    if (nIndBeg < nLen)
+        aBuf.append( pBeg + nIndBeg, nLen - nIndBeg);
+    // Append all remaining comments, preserve lines.
+    bool bNewLine = false;
+    for ( ; i < nComments; ++i)
+    {
+        if (!bNewLine)
+            aBuf.append( sal_Unicode(' '));
+        aBuf.append( rComments[i].maComment);
+        if (rComments[i].mbLastOnLine)
+        {
+            aBuf.append( sal_Unicode('\n'));
+            bNewLine = true;
+        }
+        else
+            bNewLine = false;
+    }
+    return aBuf.makeStringAndClear();
+}
 // -----------------------------------------------------------------------------
 ::rtl::OUString OQueryController::translateStatement( bool _bFireStatementChange )
 {
@@ -1601,6 +1746,8 @@ bool OQueryController::doSaveAsDoc(sal_Bool _bSaveAs)
         {
             ::rtl::OUString aErrorMsg;
 
+            ::std::vector< CommentStrip > aComments = getComment( m_sStatement);
+
             ::connectivity::OSQLParseNode* pNode = m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign );
             if(pNode)
             {
@@ -1610,6 +1757,7 @@ bool OQueryController::doSaveAsDoc(sal_Bool _bSaveAs)
 
             m_xComposer->setQuery(sTranslatedStmt);
             sTranslatedStmt = m_xComposer->getComposedQuery();
+            sTranslatedStmt = concatComment( sTranslatedStmt, aComments);
         }
         catch(const SQLException& e)
         {


More information about the Libreoffice-commits mailing list