It looks like my earlier patch does address this and also adds the
x-guid to the status command as well.

I have 2 patch files plus a necessary change to the database tables :

-- add uuid extension into PostgreSQL database
CREATE EXTENSION "uuid-ossp";
-- alter mailboxes table to add a guid and set a unique constraint on it
alter table mailboxes add guid uuid not null default uuid_generate_v4();
alter table mailboxes add constraint uniq_guid check unique (guid);

This will automatically create a random uuid for each mailbox and
enforce the uniqueness (which should be the default if the uuid
generation is any good).

I've cleaned up my original patch set and removed some redundant debug
and fragments of other stuff I was testing.  This gives 2 patch files as
the code has 2 distinct parts.  They apply with some offsets against the
current master :

Add uuid handling to the PostgreSQL code.  uuid.patch.  This could stand
by itself, though it's purpose is to lay the proper PostgreSQL handling
of uuid columns.

Add x-guid handling to STATUS and LIST commands.  xguid.patch.  This
requires uuid.patch first.

I have this running on a production server (again).  Lots of my users
are using clients which use the x-guid, so this is needed for general
use as far as I can tell.

Jim




On 09/06/2016 14:59, NSS Ltd wrote:
> OK, I knew this was familiar.  I sent a patch in April 2015 but it's not
> merged (some others I sent for some different things are merged).
>
> I need to check the code to become familiar again, but is it possible to
> get this merged in?  It may need some cleanup, but I believe it was
> working on my custom build OK for the last year, so it should be good to
> merge in after review.
>
> Jim
>
>
>
>
> On 09/06/2016 14:29, NSS Ltd wrote:
>> Hi,
>>
>> I've just updated to the latest git master and see a number of back-off
>> due to imap syntax error messages.
>>
>> The offending command seems to be :
>>
>> list "" "*" return (status (x-guid) children)
>>
>> And the 'status' seems to be the problem.
>>
>> 114 BAD Unknown return option: status
>>
>> Before digging into this, is this a known issue/something being worked
>> on?  If it's open/new, can you point me to what may be required to
>> resolve (e.g. new code/changes required)?
>>
>> Thanks
>>
>> Jim
>>
>> (There's something familiar about this - I'm not sure if this is the
>> same issue I'd had a few years back.)
>>
>>
>>
>>
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30/125 First line: 114 list
>> "" "*" return (status (x-guid) children)
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30 IMAP::runCommands, 1 commands
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30/125 Execution time 0ms
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30/125 Finished
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30 IMAP::runCommands, 1 commands
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30/125 Retired
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30/125 114 BAD Unknown return
>> option: status
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30 IMAP::runCommands, 0 commands
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30 IMAP::runCommands, 0 commands
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30/126 IMAP Command: 115 unselect
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30/126 First line: 115 unselect
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30 IMAP::runCommands, 1 commands
>> Jun  9 09:19:19 aox Archiveopteryx: 9236/2/30 Delaying next IMAP command
>> for 12 seconds (because of 12 syntax errors)
>>

diff -wur aox-master/imap/handlers/listext.cpp aox-jim/imap/handlers/listext.cpp
--- aox-master/imap/handlers/listext.cpp        2014-06-03 09:15:21.000000000 
-0400
+++ aox-jim/imap/handlers/listext.cpp   2015-04-11 15:58:14.047422000 -0400
@@ -19,19 +19,35 @@
     : public Garbage
 {
 public:
+       class statusInfo : public Garbage {
+       public:
+               uint messages;
+               uint unseen;
+               uint recent;
+               int64 nextmodseq;
+               EString guid;
+               
+                statusInfo() :
+                       messages(0), unseen(0), recent(0), nextmodseq(0) {
+                                       // Empty
+               }
+       };
+
     ListextData():
-        selectQuery( 0 ), permissionsQuery( 0 ),
-        reference( 0 ),
+        selectQuery( 0 ), permissionsQuery( 0 ), statusQuery( 0 ),
+        reference( 0 ), mailboxStatus (0),
         state( 0 ),
         extended( false ),
         returnSubscribed( false ), returnChildren( false ),
         selectSubscribed( false ), selectRemote( false ),
-        selectRecursiveMatch( false )
+        selectRecursiveMatch( false ), returnStatus( false )
     {}
 
     Query * selectQuery;
     Query * permissionsQuery;
+       Query * statusQuery;
     Mailbox * reference;
+       statusInfo * mailboxStatus;
     EString referenceName;
     UStringList patterns;
     uint state;
@@ -64,12 +80,38 @@
     EString previousResponse;
     List<Response> responses;
 
+       // Status Selection Object
+       class statusSelection : public Garbage {
+               public:
+               bool getRecent;
+               bool getMessages;
+               bool getUidNext;
+               bool getUidValidity;
+               bool getUnseen;
+               bool getHighestModSeq;
+               bool getXGuid;
+               
+
+                       statusSelection() :
+                       getRecent(false), getMessages(false), getUidNext(false),
+                       getUidValidity(false), getUnseen (false), 
getHighestModSeq (false),
+                       getXGuid ( false ) {
+                       // Empty Constructor
+               }
+       };
+
+       statusSelection statusRequired;
+       
+
+       
+
     bool extended;
     bool returnSubscribed;
     bool returnChildren;
     bool selectSubscribed;
     bool selectRemote;
     bool selectRecursiveMatch;
+       bool returnStatus;
 };
 
 
@@ -177,7 +219,7 @@
         uint bn = 1;
         EString sel;
         if ( d->selectSubscribed && d->selectRecursiveMatch ) {
-            sel = "select mb.id, mb.name, s.id as sid, "
+            sel = "with q1 as (select mb.id, mb.name, s.id as sid, "
                   "exists(select cmb.id from mailboxes cmb "
                   "join subscriptions cs on"
                   " (cmb.id=cs.mailbox and cs.owner=$1) "
@@ -192,14 +234,14 @@
             bn = 2;
         }
         else if ( d->selectSubscribed ) {
-            sel = "select mb.id, mb.name, s.id as sid from mailboxes mb "
+            sel = "with q1 as (select mb.id, mb.name, s.id as sid from 
mailboxes mb "
                   "join subscriptions s on (mb.id=s.mailbox and s.owner=$1) "
                   "where ";
             d->selectQuery->bind( 1, imap()->user()->id() );
             bn = 2;
         }
         else {
-            sel = "select mb.id, mb.name";
+            sel = "with q1 as (select mb.id, mb.name";
             if ( d->returnSubscribed ) {
                 sel.append( ", s.id as sid from mailboxes mb "
                             "left join subscriptions s on"
@@ -261,6 +303,17 @@
             ++i;
         }
         sel.append( " order by lower(mb.name)||' '" );
+               
+               // Complete Sub-Query And Add Our Own For Additional Status Info
+               sel.append( "), "
+                                       "q2 as (select q1.id, mb.guid, 
uidnext-first_recent as recent from q1 join mailboxes mb using (id)), "
+                                       "q3 as (select q1.id, count(uid) as 
unseen from q1 join mailbox_messages mm on (q1.id=mm.mailbox) where not seen 
group by id), "
+                                       "q4 as (select q1.id, count(*) as 
messages from q1 join mailbox_messages mm on (q1.id=mm.mailbox) group by id) ");
+               
+               // Now Return All Of That As A Single Query Compatible With
+               // The makeResponse Call From Before We Added The Status Feature
+               sel.append( "select * from q1 JOIN q2 using (id) join q3 using 
(id) join q4 using (id)");
+               
         d->selectQuery->setString( sel );
         d->selectQuery->execute();
 
@@ -387,10 +440,46 @@
         d->returnSubscribed = true;
     else if ( option == "children" )
         d->returnChildren = true;
-    else
+       else if ( "status" == option ) {
+               // Status Return Takes A Number Of Status Attributes We Need To 
Parse
+        d->returnStatus = true;
+               
+               require(" (");  // Status Must Be Followed By A SPACE Then (
+               
+               addStatusItem(atom().lower());  // First Status Item Is 
Mandatory
+               while ( present( " " ) )
+            addStatusItem( atom().lower() );   // Handle Any Further Items
+                       
+               require(")");   // To Complete Status, A Closing Bracket Is 
Mandatory
+               
+    } else
         error( Bad, "Unknown return option: " + option );
 }
 
+void Listext::addStatusItem( const EString & statusSelected ) {
+       if ("x-guid" == statusSelected) {
+               // X-GUID
+               d->statusRequired.getXGuid = true;
+       } else if ("messages" == statusSelected) {
+               d->statusRequired.getMessages = true;
+       } else if ("recent" == statusSelected) {
+               d->statusRequired.getRecent = true;
+       } else if ("uidnext" == statusSelected) {
+               d->statusRequired.getUidNext = true;
+       } else if ("uidvalidity" == statusSelected) {
+               d->statusRequired.getUidValidity = true;
+       } else if ("unseen" == statusSelected) {
+               d->statusRequired.getUnseen = true;
+       } else if ("highestmodseq" == statusSelected) {
+               d->statusRequired.getHighestModSeq = true;
+       } else {
+               // Nothing Valid Left - May Just Be We Don't Handle It Rather 
Than
+               // The RFC Stating It Is Illegal/Invalid.  We Log It So, If 
Debug Is
+               // Active, There Will Be A Record Of This Happening To Help
+               // Track It Down.
+               error( Bad, "Unknown status item: " + statusSelected );
+       }
+}
 
 /*! Parses the selection \a option, or emits a suitable error. \a
     option must be lower-cased. */
@@ -449,6 +538,68 @@
 
     EString name = imapQuoted( mailbox );
 
+       // Need To Append Any Extended Attributes Status ?
+       if (d->returnStatus) {
+               // yes - add them to ext
+               ext.append(" (");
+               EString preAppend = "";
+
+               if (d->statusRequired.getXGuid && row->hasColumn("guid") && 
!row->isNull("guid")) {
+                       // We want the guid and the column exists and is not 
null, so it is good to retrieve
+                       EString guid = row->getUUID("guid");
+                       ext.append(preAppend + "X-GUID " + guid);
+                       log("retrieved guid as " + guid);
+                       preAppend = " ";
+               }
+
+               if (d->statusRequired.getRecent && row->hasColumn("recent") && 
!row->isNull("recent")) {
+                       int recent = row->getInt("recent");
+                       ext.append(preAppend + "RECENT ");
+                       ext.appendNumber(recent);
+                       preAppend = " ";
+               }
+       
+               if (d->statusRequired.getUnseen && row->hasColumn("unseen") && 
!row->isNull("unseen")) {
+                       int unseen = row->getInt("unseen");
+                       ext.append(preAppend + "UNSEEN ");
+                       ext.appendNumber(unseen);
+                       preAppend = " ";
+               }
+
+               if (d->statusRequired.getMessages && row->hasColumn("messages") 
&& !row->isNull("messages")) {
+                       int messages = row->getInt("messages");
+                       ext.append(preAppend + "MESSAGES ");
+                       ext.appendNumber(messages);
+                       preAppend = " ";
+               }
+               
+               if (d->statusRequired.getUidNext) {
+                       int uidnext = mailbox->uidnext();
+                       ext.append(preAppend + "UIDNEXT ");
+                       ext.appendNumber(uidnext);
+                       preAppend = " ";
+               }               
+               
+               if (d->statusRequired.getUidValidity) {
+                       int uidvalidity = mailbox->uidvalidity();
+                       ext.append(preAppend + "UIDVALIDITY ");
+                       ext.appendNumber(uidvalidity);
+                       preAppend = " ";
+               }
+               
+               if (d->statusRequired.getHighestModSeq) {
+                       int64 highest = mailbox->nextModSeq();
+                       if (highest > 1)
+                               highest--;
+                               
+                       ext.append(preAppend + "HIGHESTMODSEQ ");
+                       ext.appendNumber(highest);
+                       preAppend = " ";
+               }
+               
+               ext.append(")");
+       }
+
     EString r = "LIST (" + a.join( " " ) + ") \"/\" " + name + ext;
 
     if ( r == d->previousResponse )
diff -wur aox-master/imap/handlers/listext.h aox-jim/imap/handlers/listext.h
--- aox-master/imap/handlers/listext.h  2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/imap/handlers/listext.h     2015-04-10 16:23:50.459422000 -0400
@@ -20,6 +20,7 @@
 private:
     void addReturnOption( const EString & );
     void addSelectOption( const EString & );
+       void addStatusItem( const EString & );
 
     void makeResponse( class Row * );
 
diff -wur aox-master/imap/handlers/status.cpp aox-jim/imap/handlers/status.cpp
--- aox-master/imap/handlers/status.cpp 2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/imap/handlers/status.cpp    2015-04-08 08:38:02.135422000 -0400
@@ -19,16 +19,17 @@
     StatusData() :
         messages( false ), uidnext( false ), uidvalidity( false ),
         recent( false ), unseen( false ),
-        modseq( false ),
+        modseq( false ), x_guid (false),
         mailbox( 0 ),
         unseenCount( 0 ), messageCount( 0 ), recentCount( 0 ),
         cacheState( 0 )
         {}
-    bool messages, uidnext, uidvalidity, recent, unseen, modseq;
+    bool messages, uidnext, uidvalidity, recent, unseen, modseq, x_guid;
     Mailbox * mailbox;
     Query * unseenCount;
     Query * messageCount;
     Query * recentCount;
+       Query * mailbox_x_guid;
     uint cacheState;
 
     class CacheItem
@@ -37,16 +38,19 @@
     public:
         CacheItem():
             hasMessages( false ), hasUnseen( false ), hasRecent( false ),
+                       has_x_guid (false),
             messages( 0 ), unseen( 0 ), recent( 0 ),
             nextmodseq( 0 ), mailbox( 0 )
             {}
         bool hasMessages;
         bool hasUnseen;
         bool hasRecent;
+               bool has_x_guid;
         uint messages;
         uint unseen;
         uint recent;
         int64 nextmodseq;
+               EString x_guid;
         Mailbox * mailbox;
     };
 
@@ -73,6 +77,7 @@
                 i->hasMessages = false;
                 i->hasUnseen = false;
                 i->hasRecent = false;
+                               i->has_x_guid = false;
             }
             return i;
         }
@@ -154,6 +159,8 @@
             d->unseen = true;
         else if ( item == "highestmodseq" )
             d->modseq = true;
+        else if ( "x-guid" == item )
+            d->x_guid = true;
         else
             error( Bad, "Unknown STATUS item: " + item );
 
@@ -189,13 +196,15 @@
 
     // second part. see if anything has happened, and feed the cache if
     // so. make sure we feed the cache at once.
-    if ( d->unseenCount || d->recentCount || d->messageCount ) {
+    if ( d->unseenCount || d->recentCount || d->messageCount || 
d->mailbox_x_guid) {
         if ( d->unseenCount && !d->unseenCount->done() )
             return;
         if ( d->messageCount && !d->messageCount->done() )
             return;
         if ( d->recentCount && !d->recentCount->done() )
             return;
+               if ( d->mailbox_x_guid && !d->mailbox_x_guid->done() )
+                       return;
     }
     if ( !::cache )
         ::cache = new StatusData::StatusCache;
@@ -233,7 +242,18 @@
             }
         }
     }
-
+    if ( d->mailbox_x_guid ) {
+               // Retrieve Mailbox GUID Value And Place Into Cache Item
+        while ( d->mailbox_x_guid->hasResults() ) {
+            Row * r = d->mailbox_x_guid->nextRow();
+            StatusData::CacheItem * ci =
+                ::cache->find( r->getInt( "mailbox" ) );
+            if ( ci ) {
+                ci->has_x_guid = true;
+                ci->x_guid = r->getEString( "guid" );
+            }
+        }
+    }
     // third part. are we processing the first command in a STATUS
     // loop? if so, see if we ought to preload the cache.
     if ( mailboxGroup() && d->cacheState < 3 ) {
@@ -244,9 +264,9 @@
             while ( i ) {
                 StatusData::CacheItem * ci = ::cache->provide( i );
                 bool need = false;
-                if ( d->unseen || d->recent || d->messages )
+                if ( d->unseen || d->recent || d->messages || d->x_guid )
                     need = true;
-                if ( ci->hasUnseen || ci->hasRecent || ci->hasMessages )
+                if ( ci->hasUnseen || ci->hasRecent || ci->hasMessages || 
ci->has_x_guid )
                     need = false;
                 if ( need )
                     mailboxes.add( i->id() );
@@ -282,6 +302,16 @@
                 d->messageCount->bind( 1, mailboxes );
                 d->messageCount->execute();
             }
+                       if ( d->x_guid ) {
+                               // Run Query To Get Mailbox GUID Value
+                d->mailbox_x_guid
+                    = new Query( "select guid "
+                                 "from mailboxes where id=any($1) "
+                                 , this );
+                d->mailbox_x_guid->bind( 1, mailboxes );
+                d->mailbox_x_guid->execute();
+            }
+                       
             d->cacheState = 2;
         }
         if ( d->cacheState == 2 ) {
@@ -296,6 +326,8 @@
                     ci->hasRecent = true;
                 if ( ci && d->messageCount )
                     ci->hasMessages = true;
+                if ( ci && d->mailbox_x_guid )
+                    ci->has_x_guid = true;
                 ++i;
             }
             // and drop the queries
@@ -303,6 +335,7 @@
             d->unseenCount = 0;
             d->recentCount = 0;
             d->messageCount = 0;
+                       d->mailbox_x_guid = NULL;       // Null is surely 
better than 0?
         }
     }
 
@@ -356,13 +389,26 @@
         d->messageCount->execute();
     }
 
-    if ( d->unseenCount || d->recentCount || d->messageCount ) {
+       // Individual guid query ?
+    if ( d->x_guid && !d->mailbox_x_guid && !i->has_x_guid ) {
+        d->mailbox_x_guid
+            = new Query( "select guid "
+                                                "from mailboxes where id=$1 "
+                         , this );
+        d->mailbox_x_guid->bind( 1, d->mailbox->id() );
+        d->mailbox_x_guid->execute();
+    }
+
+
+    if ( d->unseenCount || d->recentCount || d->messageCount || 
d->mailbox_x_guid ) {
         if ( d->unseenCount && !d->unseenCount->done() )
             return;
         if ( d->messageCount && !d->messageCount->done() )
             return;
         if ( d->recentCount && !d->recentCount->done() )
             return;
+        if ( d->mailbox_x_guid && !d->mailbox_x_guid->done() )
+            return;
     }
 
     // fifth part: return the payload.
@@ -396,6 +442,9 @@
         status.append( "HIGHESTMODSEQ " + fn( hms ) );
     }
 
+    if ( d->x_guid && i->has_x_guid )
+        status.append( "X-GUID " + i->x_guid );
+
     respond( "STATUS " + imapQuoted( d->mailbox ) +
              " (" + status.join( " " ) + ")" );
     finish();

Only in aox-jim: AOX
Only in aox-jim/aox: buildinfo.inc
diff -wur aox-master/aox/db.cpp aox-jim/aox/db.cpp
--- aox-master/aox/db.cpp       2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/aox/db.cpp  2015-04-11 08:50:12.579422000 -0400
@@ -723,6 +723,9 @@
         case Column::Timestamp:
             s.append( "(timestamptz)" );
             break;
+               case Column::Uuid:
+                       s.append( "(uuid)");
+                       break;
         case Column::Null:
             s.append( "null" );
             break;
Only in aox-jim: bin
Only in aox-jim: build
diff -wur aox-master/core/estring.h aox-jim/core/estring.h
--- aox-master/core/estring.h   2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/core/estring.h      2014-07-06 12:35:16.379058000 -0400
@@ -40,6 +40,7 @@
     EString & operator=( const EString & );
     EString & operator=( const char * );
     EString & operator+=( const EString & str ) { append( str ); return *this; 
}
+       EString & operator+=( const int64 & num ) { appendNumber(num); return 
*this; }
 
     void operator delete( void * );
 
Only in aox-jim/db: downgrades.inc
diff -wur aox-master/db/pgmessage.cpp aox-jim/db/pgmessage.cpp
--- aox-master/db/pgmessage.cpp 2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/db/pgmessage.cpp    2015-04-11 09:16:33.295422000 -0400
@@ -8,6 +8,7 @@
 #include "buffer.h"
 #include "query.h"
 
+#include "stdio.h"
 
 static bool haveAskedForCitext;
 static int citextOid;
@@ -189,6 +190,53 @@
     return s;
 }
 
+EString PgServerMessage::decodeUUID( uint x ) {
+       EString s = "";
+       
+       if (16 != x) {
+               log("uuid decode should request 16 bytes but instead requested 
" + x );
+               throw Syntax;
+       }
+       
+       uint32 data1 = ( (*buf)[0] << 24 ) |
+            ( (*buf)[1] << 16 ) |
+            ( (*buf)[2] <<  8 ) |
+            ( (*buf)[3]       );
+    buf->remove( 4 );
+    n += 4;
+       
+       uint32 data2 = ((*buf)[0] << 8) | (*buf)[1];
+       buf->remove( 2 );
+    n += 2;
+       
+       uint32 data3 = ((*buf)[0] << 8) | (*buf)[1];
+       buf->remove( 2 );
+    n += 2;
+       
+       uint32 data4 = ((*buf)[0] << 8) | (*buf)[1];
+       buf->remove( 2 );
+    n += 2;
+       
+       uint32 data5 = ((*buf)[0] << 8) | (*buf)[1];
+       buf->remove( 2 );
+    n += 2;
+       
+       
+       uint32 data6 = ( (*buf)[0] << 24 ) |
+            ( (*buf)[1] << 16 ) |
+            ( (*buf)[2] <<  8 ) |
+            ( (*buf)[3]       );
+    buf->remove( 4 );
+    n += 4;
+       
+       char result[37];
+       sprintf( result, "%08x-%04x-%04x-%04x-%04x%08x", data1, data2, data3, 
data4, data5, data6);
+       
+       s = result;
+
+       return s;
+}
+
 
 /*! This function is used by subclasses to assert that they have decoded
     the entire contents of the message. If the size of the decoded data
@@ -898,6 +946,9 @@
         case 1184:
             cv->type = Column::Timestamp;
             break;
+               case 2950:
+                       cv->type = Column::Uuid;
+                       break;
         default:
             if ( it->type == ::citextOid ) { // CITEXT
                 cv->type = Column::Bytes;
@@ -978,6 +1029,9 @@
         case Column::Timestamp:
             cv->s = decodeByten( length );
             break;
+               case Column::Uuid:
+                       cv->s = decodeUUID( length );
+                       break;
         case Column::Null:
             // nothing needed
             break;
diff -wur aox-master/db/pgmessage.h aox-jim/db/pgmessage.h
--- aox-master/db/pgmessage.h   2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/db/pgmessage.h      2015-04-11 07:50:20.871422000 -0400
@@ -33,6 +33,7 @@
     char decodeByte();
     EString decodeString();
     EString decodeByten( uint );
+       EString decodeUUID(uint);
     void end();
 };
 
Only in aox-jim/db: privileges.inc
diff -wur aox-master/db/query.cpp aox-jim/db/query.cpp
--- aox-master/db/query.cpp     2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/db/query.cpp        2015-04-11 09:20:29.359422000 -0400
@@ -855,6 +855,19 @@
     return c->bi;
 }
 
+/*! Returns the string value of the column named \a f i if it exists
+    and is NOT NULL, and an empty string otherwise.
+*/
+
+EString Row::getUUID( const char * f ) const
+{
+    const Column * c = fetch( f, Column::Uuid, true );
+    if ( !c )
+        return "";
+    if ( c->type != Column::Uuid )
+        return "";
+    return c->s;
+}
 
 /*! Returns the string value of the column named \a f i if it exists
     and is NOT NULL, and an empty string otherwise.
@@ -1009,6 +1022,9 @@
     case Timestamp:
         n = "timestamptz";
         break;
+       case Uuid:
+               n = "uuid";
+               break;
     case Null:
         n = "null";
         break;
diff -wur aox-master/db/query.h aox-jim/db/query.h
--- aox-master/db/query.h       2014-06-03 09:15:21.000000000 -0400
+++ aox-jim/db/query.h  2015-04-11 09:19:18.935422000 -0400
@@ -129,7 +129,7 @@
     : public Garbage
 {
 public:
-    enum Type { Unknown, Boolean, Integer, Bigint, Bytes, Timestamp, Null };
+    enum Type { Unknown, Boolean, Integer, Bigint, Bytes, Timestamp, Null, 
Uuid };
 
     Type type;
     EString s;
@@ -153,6 +153,7 @@
     bool getBoolean( const char * ) const;
     EString getEString( const char * ) const;
     UString getUString( const char * ) const;
+       EString getUUID( const char * ) const;
     bool hasColumn( const char * ) const;
     Column::Type columnType( const char * ) const;
 
Only in aox-jim/doc: man

Reply via email to