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

MerginMaps / geodiff / 29579363492

17 Jul 2026 12:11PM UTC coverage: 87.239% (-0.4%) from 87.592%
29579363492

Pull #252

github

web-flow
Merge 299ef3ff0 into e71dfe1a2
Pull Request #252: Allow schema changes in diffs

1163 of 1300 new or added lines in 13 files covered. (89.46%)

13 existing lines in 3 files now uncovered.

4348 of 4984 relevant lines covered (87.24%)

652.58 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 )
586✔
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 );
586✔
25
#endif
26
  if ( !mFile.is_open() )
586✔
27
    throw GeoDiffException( "Unable to open changeset file for writing: " + filename );
×
28
}
586✔
29

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

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

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

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

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

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

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

80
  for ( size_t i = 0; i < mCurrentTable.columnCount(); ++i )
5,875✔
81
  {
82
    Value::Type type = values[i].type();
4,585✔
83
    writeByte( ( char ) type );
4,585✔
84
    if ( type == Value::TypeInt ) // 0x01
4,585✔
85
    {
86
      // 64-bit int (big endian)
87
      uint64_t x;
88
      int64_t v = values[i].getInt();
1,671✔
89
      memcpy( &x, &v, 8 );
1,671✔
90
      x = htobe64( x ); // convert host to big endian
1,671✔
91
      mFile.write( reinterpret_cast<char *>( &x ), 8 );
1,671✔
92
    }
93
    else if ( type == Value::TypeDouble ) // 0x02
2,914✔
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,879✔
103
    {
104
      const std::string &str = values[i].getString();
1,621✔
105
      writeVarint( static_cast<int>( str.size() ) );
1,621✔
106
      mFile.write( str.c_str(), str.size() );
1,621✔
107
    }
1,621✔
108
    else if ( type == Value::TypeNull ) // 0x05
1,258✔
109
    {
110
      // nothing extra to write
111
    }
112
    else if ( type == Value::TypeUndefined )  // undefined value  (different from NULL)
935✔
113
    {
114
      // nothing extra to write
115
    }
116
    else
117
    {
118
      throw GeoDiffException( "unexpected entry type" );
×
119
    }
120
  }
121
}
1,290✔
122

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

137

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

145
  if ( entry.op != ( int ) ChangesetEntryType::OpInsert )
1,037✔
146
    writeRowValues( entry.oldValues );
444✔
147
  if ( entry.op != ( int ) ChangesetEntryType::OpDelete )
1,037✔
148
    writeRowValues( entry.newValues );
846✔
149
}
1,037✔
150

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

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

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

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

© 2026 Coveralls, Inc