• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MerginMaps / geodiff / 26441306127

26 May 2026 08:29AM UTC coverage: 87.996% (-0.1%) from 88.114%
26441306127

Pull #252

github

web-flow
Merge c443e2ce5 into 0a94b5ba4
Pull Request #252: Allow schema changes in diffs

1056 of 1166 new or added lines in 13 files covered. (90.57%)

13 existing lines in 3 files now uncovered.

4237 of 4815 relevant lines covered (88.0%)

610.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.44
/geodiff/src/changesetwriter.cpp
1
/*
2
 GEODIFF - MIT License
3
 Copyright (C) 2020 Martin Dobias
4
*/
5

6
#include "changesetwriter.h"
7

8
#include "changeset.h"
9
#include "geodiffutils.hpp"
10
#include "changesetputvarint.h"
11
#include "portableendian.h"
12

13
#include <assert.h>
14
#include <memory.h>
15

16
#include <sstream>
17
#include <variant>
18

19
void ChangesetWriter::open( const std::string &filename )
534✔
20
{
21
#ifdef WIN32
22
  mFile.open( stringToWString( filename ), std::ios::out | std::ios::binary );
23
#else
24
  mFile.open( filename, std::ios::out | std::ios::binary );
534✔
25
#endif
26
  if ( !mFile.is_open() )
534✔
27
    throw GeoDiffException( "Unable to open changeset file for writing: " + filename );
×
28
}
534✔
29

30
void ChangesetWriter::beginTable( const ChangesetTable &table )
515✔
31
{
32
  mCurrentTable = table;
515✔
33

34
  writeByte( ( int ) ChangesetEntryType::OpTableRecord );
515✔
35
  writeVarint( ( int ) table.columnCount() );
515✔
36
  for ( size_t i = 0; i < table.columnCount(); ++i )
2,341✔
37
    writeByte( table.primaryKeys[i] );
1,826✔
38
  writeNullTerminatedString( table.name );
515✔
39
}
515✔
40

41
void ChangesetWriter::writeEntry( const ChangesetEntry &entry )
969✔
42
{
43
  if ( const ChangesetDataEntry *dataEntry = std::get_if<ChangesetDataEntry>( &entry ) )
969✔
44
    writeDataEntry( *dataEntry );
941✔
45
  else if ( const ChangesetCreateTableEntry *ctEntry = std::get_if<ChangesetCreateTableEntry>( &entry ) )
28✔
46
    writeCreateTableEntry( *ctEntry );
8✔
47
  else if ( const ChangesetDropTableEntry *dtEntry = std::get_if<ChangesetDropTableEntry>( &entry ) )
20✔
48
    writeDropTableEntry( *dtEntry );
6✔
49
  else if ( const ChangesetAddColumnEntry *acEntry = std::get_if<ChangesetAddColumnEntry>( &entry ) )
14✔
50
    writeAddColumnEntry( *acEntry );
8✔
51
  else if ( const ChangesetDropColumnEntry *dcEntry = std::get_if<ChangesetDropColumnEntry>( &entry ) )
6✔
52
    writeDropColumnEntry( *dcEntry );
6✔
53
  else
NEW
54
    throw GeoDiffException( "Tried to write unhandled changeset entry type! " +
×
NEW
55
                            std::to_string( entry.index() ) );
×
56
}
969✔
57

58
void ChangesetWriter::writeByte( char c )
8,509✔
59
{
60
  mFile.write( &c, 1 );
8,509✔
61
}
8,509✔
62

63
void ChangesetWriter::writeVarint( int n )
2,094✔
64
{
65
  unsigned char output[9];  // 1-9 bytes
66
  int numBytes = putVarint32( output, n );
2,094✔
67
  mFile.write( reinterpret_cast<char *>( output ), numBytes );
2,094✔
68
}
2,094✔
69

70
void ChangesetWriter::writeNullTerminatedString( const std::string &str )
655✔
71
{
72
  mFile.write( str.c_str(), str.size() + 1 );
655✔
73
}
655✔
74

75
void ChangesetWriter::writeRowValues( const std::vector<Value> &values )
1,161✔
76
{
77
  if ( values.size() != mCurrentTable.columnCount() )
1,161✔
78
    throw GeoDiffException( "wrong number of rows in the entry" );
×
79

80
  for ( size_t i = 0; i < mCurrentTable.columnCount(); ++i )
5,307✔
81
  {
82
    Value::Type type = values[i].type();
4,146✔
83
    writeByte( ( char ) type );
4,146✔
84
    if ( type == Value::TypeInt ) // 0x01
4,146✔
85
    {
86
      // 64-bit int (big endian)
87
      uint64_t x;
88
      int64_t v = values[i].getInt();
1,545✔
89
      memcpy( &x, &v, 8 );
1,545✔
90
      x = htobe64( x ); // convert host to big endian
1,545✔
91
      mFile.write( reinterpret_cast<char *>( &x ), 8 );
1,545✔
92
    }
93
    else if ( type == Value::TypeDouble ) // 0x02
2,601✔
94
    {
95
      // 64-bit double (big endian)
96
      int64_t x;
97
      double v = values[i].getDouble();
35✔
98
      memcpy( &x, &v, 8 );
35✔
99
      x = htobe64( x ); // convert host to big endian
35✔
100
      mFile.write( reinterpret_cast<char *>( &x ), 8 );
35✔
101
    }
102
    else if ( type == Value::TypeText || type == Value::TypeBlob ) // 0x03 or 0x04
2,566✔
103
    {
104
      const std::string &str = values[i].getString();
1,509✔
105
      writeVarint( static_cast<int>( str.size() ) );
1,509✔
106
      mFile.write( str.c_str(), str.size() );
1,509✔
107
    }
1,509✔
108
    else if ( type == Value::TypeNull ) // 0x05
1,057✔
109
    {
110
      // nothing extra to write
111
    }
112
    else if ( type == Value::TypeUndefined )  // undefined value  (different from NULL)
806✔
113
    {
114
      // nothing extra to write
115
    }
116
    else
117
    {
118
      throw GeoDiffException( "unexpected entry type" );
×
119
    }
120
  }
121
}
1,161✔
122

123
void ChangesetWriter::writeColumnInfo( const TableColumnInfo &column )
56✔
124
{
125
  writeNullTerminatedString( column.name );
56✔
126
  writeByte( static_cast<char>( column.type.baseType ) );
56✔
127
  writeByte( ( column.isPrimaryKey << 0 )
56✔
128
             | ( column.isNotNull << 1 )
56✔
129
             | ( column.isAutoIncrement << 2 )
56✔
130
             | ( column.isGeometry << 3 )
56✔
131
             | ( column.geomHasZ << 4 )
56✔
132
             | ( column.geomHasM << 5 ) );
56✔
133
  writeNullTerminatedString( column.geomType );
56✔
134
  writeVarint( column.geomSrsId );
56✔
135
}
56✔
136

137

138
void ChangesetWriter::writeDataEntry( const ChangesetDataEntry &entry )
941✔
139
{
140
  if ( entry.op != ChangesetDataEntry::OpInsert && entry.op != ChangesetDataEntry::OpUpdate && entry.op != ChangesetDataEntry::OpDelete )
941✔
NEW
141
    throw GeoDiffException( "wrong op for changeset entry" );
×
142
  writeByte( ( char ) entry.op );
941✔
143
  writeByte( 0 );  // "indirect" always false
941✔
144

145
  if ( entry.op != ( int ) ChangesetEntryType::OpInsert )
941✔
146
    writeRowValues( entry.oldValues );
392✔
147
  if ( entry.op != ( int ) ChangesetEntryType::OpDelete )
941✔
148
    writeRowValues( entry.newValues );
769✔
149
}
941✔
150

151
void ChangesetWriter::writeCreateTableEntry( const ChangesetCreateTableEntry &entry )
8✔
152
{
153
  writeByte( static_cast<char>( ChangesetEntryType::OpCreateTable ) );
8✔
154
  writeNullTerminatedString( entry.tableName );
8✔
155
  writeVarint( static_cast<int>( entry.columns.size() ) );
8✔
156
  for ( const TableColumnInfo &column : entry.columns )
32✔
157
  {
158
    writeColumnInfo( column );
24✔
159
  }
160
}
8✔
161

162
void ChangesetWriter::writeDropTableEntry( const ChangesetDropTableEntry &entry )
6✔
163
{
164
  writeByte( static_cast<char>( ChangesetEntryType::OpDropTable ) );
6✔
165
  writeNullTerminatedString( entry.tableName );
6✔
166
  writeVarint( static_cast<int>( entry.columns.size() ) );
6✔
167
  for ( const TableColumnInfo &column : entry.columns )
24✔
168
  {
169
    writeColumnInfo( column );
18✔
170
  }
171
}
6✔
172

173
void ChangesetWriter::writeAddColumnEntry( const ChangesetAddColumnEntry &entry )
8✔
174
{
175
  writeByte( static_cast<char>( ChangesetEntryType::OpAddColumn ) );
8✔
176
  writeNullTerminatedString( entry.tableName );
8✔
177
  writeColumnInfo( entry.column );
8✔
178
}
8✔
179

180
void ChangesetWriter::writeDropColumnEntry( const ChangesetDropColumnEntry &entry )
6✔
181
{
182
  writeByte( static_cast<char>( ChangesetEntryType::OpDropColumn ) );
6✔
183
  writeNullTerminatedString( entry.tableName );
6✔
184
  writeColumnInfo( entry.column );
6✔
185
}
6✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc