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

MerginMaps / geodiff / 30586949999

30 Jul 2026 10:23PM UTC coverage: 87.091% (-0.5%) from 87.592%
30586949999

Pull #252

github

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

1317 of 1483 new or added lines in 13 files covered. (88.81%)

15 existing lines in 4 files now uncovered.

4473 of 5136 relevant lines covered (87.09%)

677.01 hits per line

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

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

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

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

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

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

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

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

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

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

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

137

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

145
  if ( entry.op != ( int ) ChangesetEntryType::OpInsert )
1,076✔
146
    writeRowValues( entry.oldValues );
482✔
147
  if ( entry.op != ( int ) ChangesetEntryType::OpDelete )
1,076✔
148
    writeRowValues( entry.newValues );
883✔
149
}
1,076✔
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 )
36✔
174
{
175
  writeByte( static_cast<char>( ChangesetEntryType::OpAddColumn ) );
36✔
176
  writeNullTerminatedString( entry.tableName );
36✔
177
  writeVarint( entry.columnIdx );
36✔
178
  writeColumnInfo( entry.column );
36✔
179
}
36✔
180

181
void ChangesetWriter::writeDropColumnEntry( const ChangesetDropColumnEntry &entry )
19✔
182
{
183
  writeByte( static_cast<char>( ChangesetEntryType::OpDropColumn ) );
19✔
184
  writeNullTerminatedString( entry.tableName );
19✔
185
  writeVarint( entry.columnIdx );
19✔
186
  writeColumnInfo( entry.column );
19✔
187
}
19✔
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