~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_wc/wc_db.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
#include <apr_pools.h>
28
28
#include <apr_hash.h>
29
29
 
 
30
#include "svn_private_config.h"
30
31
#include "svn_types.h"
31
32
#include "svn_error.h"
32
33
#include "svn_dirent_uri.h"
48
49
#include "workqueue.h"
49
50
#include "token-map.h"
50
51
 
51
 
#include "svn_private_config.h"
 
52
#include "private/svn_sorts_private.h"
52
53
#include "private/svn_sqlite.h"
53
54
#include "private/svn_skel.h"
54
55
#include "private/svn_wc_private.h"
277
278
               apr_pool_t *scratch_pool);
278
279
 
279
280
static svn_error_t *
280
 
set_actual_props(apr_int64_t wc_id,
 
281
set_actual_props(svn_wc__db_wcroot_t *wcroot,
281
282
                 const char *local_relpath,
282
283
                 apr_hash_t *props,
283
 
                 svn_sqlite__db_t *db,
284
284
                 apr_pool_t *scratch_pool);
285
285
 
286
286
static svn_error_t *
354
354
                          svn_wc__db_status_t status);
355
355
 
356
356
static svn_error_t *
357
 
wclock_owns_lock(svn_boolean_t *own_lock,
358
 
                 svn_wc__db_wcroot_t *wcroot,
359
 
                 const char *local_relpath,
360
 
                 svn_boolean_t exact,
361
 
                 apr_pool_t *scratch_pool);
362
 
 
363
 
static svn_error_t *
364
357
db_is_switched(svn_boolean_t *is_switched,
365
358
               svn_node_kind_t *kind,
366
359
               svn_wc__db_wcroot_t *wcroot,
424
417
svn_error_t *
425
418
svn_wc__db_fetch_repos_info(const char **repos_root_url,
426
419
                            const char **repos_uuid,
427
 
                            svn_sqlite__db_t *sdb,
 
420
                            svn_wc__db_wcroot_t *wcroot,
428
421
                            apr_int64_t repos_id,
429
422
                            apr_pool_t *result_pool)
430
423
{
443
436
      return SVN_NO_ERROR;
444
437
    }
445
438
 
446
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
 
439
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
447
440
                                    STMT_SELECT_REPOSITORY_BY_ID));
448
441
  SVN_ERR(svn_sqlite__bindf(stmt, "i", repos_id));
449
442
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
493
486
    }
494
487
}
495
488
 
496
 
 
497
 
/* Get the statement given by STMT_IDX, and bind the appropriate wc_id and
498
 
   local_relpath based upon LOCAL_ABSPATH.  Store it in *STMT, and use
499
 
   SCRATCH_POOL for temporary allocations.
500
 
 
501
 
   Note: WC_ID and LOCAL_RELPATH must be arguments 1 and 2 in the statement. */
502
 
static svn_error_t *
503
 
get_statement_for_path(svn_sqlite__stmt_t **stmt,
504
 
                       svn_wc__db_t *db,
505
 
                       const char *local_abspath,
506
 
                       int stmt_idx,
507
 
                       apr_pool_t *scratch_pool)
508
 
{
509
 
  svn_wc__db_wcroot_t *wcroot;
510
 
  const char *local_relpath;
511
 
 
512
 
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
513
 
 
514
 
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
515
 
                              local_abspath, scratch_pool, scratch_pool));
516
 
  VERIFY_USABLE_WCROOT(wcroot);
517
 
 
518
 
  SVN_ERR(svn_sqlite__get_statement(stmt, wcroot->sdb, stmt_idx));
519
 
  SVN_ERR(svn_sqlite__bindf(*stmt, "is", wcroot->wc_id, local_relpath));
520
 
 
521
 
  return SVN_NO_ERROR;
522
 
}
523
 
 
524
 
 
525
489
/* For a given REPOS_ROOT_URL/REPOS_UUID pair, return the existing REPOS_ID
526
490
   value. If one does not exist, then create a new one. */
527
491
static svn_error_t *
575
539
}
576
540
 
577
541
 
578
 
svn_error_t *
579
 
svn_wc__db_extend_parent_delete(svn_wc__db_wcroot_t *wcroot,
580
 
                                const char *local_relpath,
581
 
                                svn_node_kind_t kind,
582
 
                                int op_depth,
583
 
                                apr_pool_t *scratch_pool)
 
542
/* Extend any delete of the parent of LOCAL_RELPATH to LOCAL_RELPATH.
 
543
 
 
544
   ### What about KIND and OP_DEPTH?  KIND ought to be redundant; I'm
 
545
       discussing on dev@ whether we can let that be null for presence
 
546
       == base-deleted.  OP_DEPTH is the op-depth of what, and why?
 
547
       It is used to select the lowest working node higher than OP_DEPTH,
 
548
       so, in terms of the API, OP_DEPTH means ...?
 
549
 
 
550
   Given a wc:
 
551
 
 
552
              0         1         2         3         4
 
553
              normal
 
554
   A          normal
 
555
   A/B        normal              normal
 
556
   A/B/C                          not-pres  normal
 
557
   A/B/C/D                                            normal
 
558
 
 
559
   That is checkout, delete A/B, copy a replacement A/B, delete copied
 
560
   child A/B/C, add replacement A/B/C, add A/B/C/D.
 
561
 
 
562
   Now an update that adds base nodes for A/B/C, A/B/C/D and A/B/C/D/E
 
563
   must extend the A/B deletion:
 
564
 
 
565
              0         1         2         3         4
 
566
              normal
 
567
   A          normal
 
568
   A/B        normal              normal
 
569
   A/B/C      normal              not-pres  normal
 
570
   A/B/C/D    normal              base-del            normal
 
571
   A/B/C/D/E  normal              base-del
 
572
 
 
573
   When adding a node if the parent has a higher working node then the
 
574
   parent node is deleted (or replaced) and the delete must be extended
 
575
   to cover new node.
 
576
 
 
577
   In the example above A/B/C/D and A/B/C/D/E are the nodes that get
 
578
   the extended delete, A/B/C is already deleted.
 
579
 
 
580
   If ADDED_DELETE is not NULL, set *ADDED_DELETE to TRUE if a new delete
 
581
   was recorded, otherwise to FALSE.
 
582
 */
 
583
static svn_error_t *
 
584
db_extend_parent_delete(svn_wc__db_wcroot_t *wcroot,
 
585
                        const char *local_relpath,
 
586
                        svn_node_kind_t kind,
 
587
                        int op_depth,
 
588
                        apr_pool_t *scratch_pool)
584
589
{
585
590
  svn_boolean_t have_row;
586
591
  svn_sqlite__stmt_t *stmt;
622
627
}
623
628
 
624
629
 
625
 
/* This is the reverse of svn_wc__db_extend_parent_delete.
 
630
/* This is the reverse of db_extend_parent_delete.
626
631
 
627
632
   When removing a node if the parent has a higher working node then
628
633
   the parent node and this node are both deleted or replaced and any
632
637
   only uses this function within an sqlite transaction if atomic
633
638
   behavior is needed.
634
639
 */
635
 
svn_error_t *
636
 
svn_wc__db_retract_parent_delete(svn_wc__db_wcroot_t *wcroot,
637
 
                                 const char *local_relpath,
638
 
                                 int op_depth,
639
 
                                 apr_pool_t *scratch_pool)
 
640
static svn_error_t *
 
641
db_retract_parent_delete(svn_wc__db_wcroot_t *wcroot,
 
642
                         const char *local_relpath,
 
643
                         int op_depth,
 
644
                         apr_pool_t *scratch_pool)
640
645
{
641
646
  svn_sqlite__stmt_t *stmt;
642
647
  svn_boolean_t have_row;
825
830
            new_actual_props = NULL;
826
831
        }
827
832
 
828
 
      SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath, new_actual_props,
829
 
                               wcroot->sdb, scratch_pool));
 
833
      SVN_ERR(set_actual_props(wcroot, local_relpath, new_actual_props,
 
834
                               scratch_pool));
830
835
    }
831
836
 
832
837
  if (pibb->kind == svn_node_dir && pibb->children)
847
852
              || (pibb->status == svn_wc__db_status_incomplete))
848
853
          && ! pibb->file_external)
849
854
        {
850
 
          SVN_ERR(svn_wc__db_extend_parent_delete(wcroot, local_relpath,
851
 
                                                  pibb->kind, 0,
852
 
                                                  scratch_pool));
 
855
          SVN_ERR(db_extend_parent_delete(wcroot, local_relpath,
 
856
                                          pibb->kind, 0,
 
857
                                          scratch_pool));
853
858
        }
854
859
      else if (pibb->status == svn_wc__db_status_not_present
855
860
               || pibb->status == svn_wc__db_status_server_excluded
856
861
               || pibb->status == svn_wc__db_status_excluded)
857
862
        {
858
 
          SVN_ERR(svn_wc__db_retract_parent_delete(wcroot, local_relpath, 0,
859
 
                                                   scratch_pool));
 
863
          SVN_ERR(db_retract_parent_delete(wcroot, local_relpath, 0,
 
864
                                           scratch_pool));
860
865
        }
861
866
    }
862
867
 
1101
1106
            new_actual_props = NULL;
1102
1107
        }
1103
1108
 
1104
 
      SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath, new_actual_props,
1105
 
                               wcroot->sdb, scratch_pool));
 
1109
      SVN_ERR(set_actual_props(wcroot, local_relpath, new_actual_props,
 
1110
                               scratch_pool));
1106
1111
    }
1107
1112
 
1108
1113
  if (piwb->kind == svn_node_dir)
1148
1153
}
1149
1154
 
1150
1155
 
1151
 
/* Each name is allocated in RESULT_POOL and stored into CHILDREN as a key
1152
 
   pointed to the same name.  */
1153
 
static svn_error_t *
1154
 
add_children_to_hash(apr_hash_t *children,
1155
 
                     int stmt_idx,
1156
 
                     svn_sqlite__db_t *sdb,
1157
 
                     apr_int64_t wc_id,
1158
 
                     const char *parent_relpath,
1159
 
                     apr_pool_t *result_pool)
1160
 
{
1161
 
  svn_sqlite__stmt_t *stmt;
1162
 
  svn_boolean_t have_row;
1163
 
 
1164
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, stmt_idx));
1165
 
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, parent_relpath));
1166
 
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
1167
 
  while (have_row)
1168
 
    {
1169
 
      const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
1170
 
      const char *name = svn_relpath_basename(child_relpath, result_pool);
1171
 
 
1172
 
      svn_hash_sets(children, name, name);
1173
 
 
1174
 
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
1175
 
    }
1176
 
 
1177
 
  return svn_sqlite__reset(stmt);
1178
 
}
1179
 
 
1180
 
 
1181
 
/* Set *CHILDREN to a new array of the (const char *) basenames of the
1182
 
   immediate children, whatever their status, of the working node at
1183
 
   LOCAL_RELPATH. */
1184
 
static svn_error_t *
1185
 
gather_children2(const apr_array_header_t **children,
1186
 
                 svn_wc__db_wcroot_t *wcroot,
1187
 
                 const char *local_relpath,
1188
 
                 apr_pool_t *result_pool,
1189
 
                 apr_pool_t *scratch_pool)
1190
 
{
1191
 
  apr_hash_t *names_hash = apr_hash_make(scratch_pool);
1192
 
  apr_array_header_t *names_array;
1193
 
 
1194
 
  /* All of the names get allocated in RESULT_POOL.  It
1195
 
     appears to be faster to use the hash to remove duplicates than to
1196
 
     use DISTINCT in the SQL query. */
1197
 
  SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_WORKING_CHILDREN,
1198
 
                               wcroot->sdb, wcroot->wc_id,
1199
 
                               local_relpath, result_pool));
1200
 
 
1201
 
  SVN_ERR(svn_hash_keys(&names_array, names_hash, result_pool));
1202
 
  *children = names_array;
1203
 
  return SVN_NO_ERROR;
1204
 
}
1205
 
 
1206
1156
/* Return in *CHILDREN all of the children of the directory LOCAL_RELPATH,
1207
1157
   of any status, in all op-depths in the NODES table. */
1208
1158
static svn_error_t *
1209
1159
gather_children(const apr_array_header_t **children,
1210
1160
                svn_wc__db_wcroot_t *wcroot,
1211
 
                const char *local_relpath,
 
1161
                const char *parent_relpath,
 
1162
                int stmt_idx,
 
1163
                int op_depth,
1212
1164
                apr_pool_t *result_pool,
1213
1165
                apr_pool_t *scratch_pool)
1214
1166
{
1215
 
  apr_hash_t *names_hash = apr_hash_make(scratch_pool);
1216
 
  apr_array_header_t *names_array;
1217
 
 
1218
 
  /* All of the names get allocated in RESULT_POOL.  It
1219
 
     appears to be faster to use the hash to remove duplicates than to
1220
 
     use DISTINCT in the SQL query. */
1221
 
  SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_NODE_CHILDREN,
1222
 
                               wcroot->sdb, wcroot->wc_id,
1223
 
                               local_relpath, result_pool));
1224
 
 
1225
 
  SVN_ERR(svn_hash_keys(&names_array, names_hash, result_pool));
1226
 
  *children = names_array;
1227
 
  return SVN_NO_ERROR;
1228
 
}
1229
 
 
1230
 
 
1231
 
/* Set *CHILDREN to a new array of (const char *) names of the children of
1232
 
   the repository directory corresponding to WCROOT:LOCAL_RELPATH:OP_DEPTH -
1233
 
   that is, only the children that are at the same op-depth as their parent. */
1234
 
static svn_error_t *
1235
 
gather_repo_children(const apr_array_header_t **children,
1236
 
                     svn_wc__db_wcroot_t *wcroot,
1237
 
                     const char *local_relpath,
1238
 
                     int op_depth,
1239
 
                     apr_pool_t *result_pool,
1240
 
                     apr_pool_t *scratch_pool)
1241
 
{
1242
 
  apr_array_header_t *result
1243
 
    = apr_array_make(result_pool, 0, sizeof(const char *));
 
1167
  apr_array_header_t *result;
1244
1168
  svn_sqlite__stmt_t *stmt;
1245
1169
  svn_boolean_t have_row;
1246
1170
 
1247
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
1248
 
                                    STMT_SELECT_OP_DEPTH_CHILDREN));
1249
 
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
1250
 
                            op_depth));
 
1171
  result = apr_array_make(result_pool, 16, sizeof(const char*));
 
1172
 
 
1173
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, stmt_idx));
 
1174
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
 
1175
  if (op_depth >= 0)
 
1176
    SVN_ERR(svn_sqlite__bind_int(stmt, 3, op_depth));
 
1177
 
1251
1178
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
1252
1179
  while (have_row)
1253
1180
    {
1254
1181
      const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
 
1182
      const char *name = svn_relpath_basename(child_relpath, result_pool);
1255
1183
 
1256
 
      /* Allocate the name in RESULT_POOL so we won't have to copy it. */
1257
 
      APR_ARRAY_PUSH(result, const char *)
1258
 
        = svn_relpath_basename(child_relpath, result_pool);
 
1184
      APR_ARRAY_PUSH(result, const char *) = name;
1259
1185
 
1260
1186
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
1261
1187
    }
 
1188
 
1262
1189
  SVN_ERR(svn_sqlite__reset(stmt));
1263
 
 
1264
1190
  *children = result;
1265
1191
  return SVN_NO_ERROR;
1266
1192
}
1267
1193
 
1268
 
svn_error_t *
1269
 
svn_wc__db_get_children_op_depth(apr_hash_t **children,
1270
 
                                 svn_wc__db_wcroot_t *wcroot,
1271
 
                                 const char *local_relpath,
1272
 
                                 int op_depth,
1273
 
                                 apr_pool_t *result_pool,
1274
 
                                 apr_pool_t *scratch_pool)
1275
 
{
1276
 
  svn_sqlite__stmt_t *stmt;
1277
 
  svn_boolean_t have_row;
1278
 
 
1279
 
  *children = apr_hash_make(result_pool);
1280
 
 
1281
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
1282
 
                                    STMT_SELECT_OP_DEPTH_CHILDREN));
1283
 
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
1284
 
                            op_depth));
1285
 
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
1286
 
  while (have_row)
1287
 
    {
1288
 
      const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
1289
 
      svn_node_kind_t *child_kind = apr_palloc(result_pool, sizeof(svn_node_kind_t));
1290
 
 
1291
 
      *child_kind = svn_sqlite__column_token(stmt, 1, kind_map);
1292
 
      svn_hash_sets(*children,
1293
 
                    svn_relpath_basename(child_relpath, result_pool),
1294
 
                    child_kind);
1295
 
 
1296
 
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
1297
 
    }
1298
 
  SVN_ERR(svn_sqlite__reset(stmt));
1299
 
 
1300
 
  return SVN_NO_ERROR;
1301
 
}
1302
 
 
1303
 
 
1304
1194
/* Return TRUE if CHILD_ABSPATH is an immediate child of PARENT_ABSPATH.
1305
1195
 * Else, return FALSE. */
1306
1196
static svn_boolean_t
1358
1248
           hi;
1359
1249
           hi = apr_hash_next(hi))
1360
1250
        {
1361
 
          const char *item_abspath = svn__apr_hash_index_key(hi);
 
1251
          const char *item_abspath = apr_hash_this_key(hi);
1362
1252
 
1363
1253
          if ((depth == svn_depth_files || depth == svn_depth_immediates) &&
1364
1254
              is_immediate_child_path(local_abspath, item_abspath))
1485
1375
  SVN_ERR(svn_sqlite__exec_statements(db, STMT_CREATE_NODES_TRIGGERS));
1486
1376
  SVN_ERR(svn_sqlite__exec_statements(db, STMT_CREATE_EXTERNALS));
1487
1377
 
 
1378
  SVN_ERR(svn_wc__db_install_schema_statistics(db, scratch_pool));
 
1379
 
1488
1380
  /* Insert the repository. */
1489
1381
  SVN_ERR(create_repos_id(repos_id, repos_root_url, repos_uuid,
1490
1382
                          db, scratch_pool));
1491
1383
 
1492
 
  SVN_ERR(svn_wc__db_install_schema_statistics(db, scratch_pool));
1493
 
 
1494
1384
  /* Insert the wcroot. */
1495
1385
  /* ### Right now, this just assumes wc metadata is being stored locally. */
1496
1386
  SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_WCROOT));
1508
1398
                                *wc_id,              /* 1 */
1509
1399
                                "",                  /* 2 */
1510
1400
                                0,                   /* op_depth is 0 for base */
1511
 
                                NULL,                /* 4 */
 
1401
                                SVN_VA_NULL,         /* 4 */
1512
1402
                                *repos_id,
1513
1403
                                root_node_repos_relpath,
1514
1404
                                root_node_revision,
1544
1434
          svn_revnum_t root_node_revision,
1545
1435
          svn_depth_t root_node_depth,
1546
1436
          svn_boolean_t exclusive,
 
1437
          apr_int32_t timeout,
1547
1438
          apr_pool_t *result_pool,
1548
1439
          apr_pool_t *scratch_pool)
1549
1440
{
1550
1441
  SVN_ERR(svn_wc__db_util_open_db(sdb, dir_abspath, sdb_fname,
1551
1442
                                  svn_sqlite__mode_rwcreate, exclusive,
 
1443
                                  timeout,
1552
1444
                                  NULL /* my_statements */,
1553
1445
                                  result_pool, scratch_pool));
1554
1446
 
1577
1469
  apr_int64_t wc_id;
1578
1470
  svn_wc__db_wcroot_t *wcroot;
1579
1471
  svn_boolean_t sqlite_exclusive = FALSE;
 
1472
  apr_int32_t sqlite_timeout = 0; /* default timeout */
 
1473
  apr_hash_index_t *hi;
1580
1474
 
1581
1475
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
1582
1476
  SVN_ERR_ASSERT(repos_relpath != NULL);
1587
1481
 
1588
1482
  /* ### REPOS_ROOT_URL and REPOS_UUID may be NULL. ... more doc: tbd  */
1589
1483
 
1590
 
  SVN_ERR(svn_config_get_bool((svn_config_t *)db->config, &sqlite_exclusive,
 
1484
  SVN_ERR(svn_config_get_bool(db->config, &sqlite_exclusive,
1591
1485
                              SVN_CONFIG_SECTION_WORKING_COPY,
1592
1486
                              SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE,
1593
1487
                              FALSE));
1596
1490
  SVN_ERR(create_db(&sdb, &repos_id, &wc_id, local_abspath, repos_root_url,
1597
1491
                    repos_uuid, SDB_FILE,
1598
1492
                    repos_relpath, initial_rev, depth, sqlite_exclusive,
 
1493
                    sqlite_timeout,
1599
1494
                    db->state_pool, scratch_pool));
1600
1495
 
1601
1496
  /* Create the WCROOT for this directory.  */
1603
1498
                        apr_pstrdup(db->state_pool, local_abspath),
1604
1499
                        sdb, wc_id, FORMAT_FROM_SDB,
1605
1500
                        FALSE /* auto-upgrade */,
1606
 
                        FALSE /* enforce_empty_wq */,
1607
1501
                        db->state_pool, scratch_pool));
1608
1502
 
 
1503
  /* Any previously cached children may now have a new WCROOT, most likely that
 
1504
     of the new WCROOT, but there might be descendant directories that are their
 
1505
     own working copy, in which case setting WCROOT to our new WCROOT might
 
1506
     actually break things for those.
 
1507
 
 
1508
     Clearing is the safest thing we can do in this case, as a test would lead
 
1509
     to unnecessary probing, while the standard code probes later anyway. So we
 
1510
     only lose a bit of memory
 
1511
 
 
1512
     ### Perhaps we could check wcroot->abspath to detect which case we have
 
1513
         where, but currently it is already very hard to trigger this from
 
1514
         the short living 'svn' client. (GUI clients like TortoiseSVN are far
 
1515
         more likely to get in these cases)
 
1516
     */
 
1517
  for (hi = apr_hash_first(scratch_pool, db->dir_data);
 
1518
       hi;
 
1519
       hi = apr_hash_next(hi))
 
1520
    {
 
1521
      const char *abspath = apr_hash_this_key(hi);
 
1522
      if (svn_dirent_is_ancestor(wcroot->abspath, abspath))
 
1523
        svn_hash_sets(db->dir_data, abspath, NULL);
 
1524
    }
 
1525
 
1609
1526
  /* The WCROOT is complete. Stash it into DB.  */
1610
1527
  svn_hash_sets(db->dir_data, wcroot->abspath, wcroot);
1611
1528
 
1714
1631
                              const apr_array_header_t *children,
1715
1632
                              svn_depth_t depth,
1716
1633
                              apr_hash_t *dav_cache,
1717
 
                              const svn_skel_t *conflict,
1718
1634
                              svn_boolean_t update_actual_props,
1719
1635
                              apr_hash_t *new_actual_props,
1720
1636
                              apr_array_header_t *new_iprops,
 
1637
                              const svn_skel_t *conflict,
1721
1638
                              const svn_skel_t *work_items,
1722
1639
                              apr_pool_t *scratch_pool)
1723
1640
{
2126
2043
}
2127
2044
 
2128
2045
/* Recursively clear moved-here information at the copy-half of the move
2129
 
 * which moved the node at SRC_RELPATH away. This transforms the move into
2130
 
 * a simple copy. */
 
2046
 * which moved a node to MOVED_TO_RELPATH. This transforms this side of the
 
2047
 * move into a simple copy.
 
2048
 */
2131
2049
static svn_error_t *
2132
 
clear_moved_here(const char *src_relpath,
2133
 
                 svn_wc__db_wcroot_t *wcroot,
 
2050
clear_moved_here(svn_wc__db_wcroot_t *wcroot,
 
2051
                 const char *moved_to_relpath,
2134
2052
                 apr_pool_t *scratch_pool)
2135
2053
{
2136
2054
  svn_sqlite__stmt_t *stmt;
2137
 
  const char *dst_relpath;
2138
 
 
2139
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_MOVED_TO));
2140
 
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
2141
 
                            src_relpath, relpath_depth(src_relpath)));
2142
 
  SVN_ERR(svn_sqlite__step_row(stmt));
2143
 
  dst_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
2144
 
  SVN_ERR(svn_sqlite__reset(stmt));
 
2055
  int affected_rows;
2145
2056
 
2146
2057
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
2147
2058
                                    STMT_CLEAR_MOVED_HERE_RECURSIVE));
2148
 
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
2149
 
                            dst_relpath, relpath_depth(dst_relpath)));
2150
 
  SVN_ERR(svn_sqlite__step_done(stmt));
2151
 
 
2152
 
  return SVN_NO_ERROR;
2153
 
}
 
2059
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, moved_to_relpath,
 
2060
                            relpath_depth(moved_to_relpath)));
 
2061
 
 
2062
  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
2063
 
 
2064
  if (affected_rows == 0)
 
2065
     return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
 
2066
                              _("The node '%s' was not found."),
 
2067
                              path_for_error_message(wcroot, moved_to_relpath,
 
2068
                                                     scratch_pool));
 
2069
 
 
2070
  return SVN_NO_ERROR;
 
2071
}
 
2072
 
 
2073
svn_error_t *
 
2074
svn_wc__db_op_break_move_internal(svn_wc__db_wcroot_t *wcroot,
 
2075
                                  const char *src_relpath,
 
2076
                                  int delete_op_depth,
 
2077
                                  const char *dst_relpath,
 
2078
                                  const svn_skel_t *work_items,
 
2079
                                  apr_pool_t *scratch_pool)
 
2080
{
 
2081
  svn_sqlite__stmt_t *stmt;
 
2082
  int affected;
 
2083
 
 
2084
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
2085
                                    STMT_CLEAR_MOVED_TO_RELPATH));
 
2086
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, src_relpath,
 
2087
                            delete_op_depth));
 
2088
  SVN_ERR(svn_sqlite__update(&affected, stmt));
 
2089
 
 
2090
  if (affected != 1)
 
2091
    return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
 
2092
                             _("Path '%s' is not moved"),
 
2093
                             path_for_error_message(wcroot, src_relpath,
 
2094
                                                    scratch_pool));
 
2095
 
 
2096
  SVN_ERR(clear_moved_here(wcroot, dst_relpath, scratch_pool));
 
2097
 
 
2098
  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
 
2099
  return SVN_NO_ERROR;
 
2100
}
 
2101
 
2154
2102
 
2155
2103
/* The body of svn_wc__db_base_remove().
2156
2104
 */
2159
2107
               const char *local_relpath,
2160
2108
               svn_wc__db_t *db, /* For checking conflicts */
2161
2109
               svn_boolean_t keep_as_working,
2162
 
               svn_boolean_t queue_deletes,
2163
 
               svn_boolean_t remove_locks,
2164
 
               svn_revnum_t not_present_revision,
 
2110
               svn_boolean_t mark_not_present,
 
2111
               svn_boolean_t mark_excluded,
 
2112
               svn_revnum_t marker_revision,
2165
2113
               svn_skel_t *conflict,
2166
2114
               svn_skel_t *work_items,
2167
2115
               apr_pool_t *scratch_pool)
2169
2117
  svn_sqlite__stmt_t *stmt;
2170
2118
  svn_boolean_t have_row;
2171
2119
  svn_wc__db_status_t status;
 
2120
  svn_revnum_t revision;
2172
2121
  apr_int64_t repos_id;
2173
2122
  const char *repos_relpath;
2174
2123
  svn_node_kind_t kind;
2175
2124
  svn_boolean_t keep_working;
 
2125
  int op_depth;
 
2126
  svn_node_kind_t wrk_kind;
 
2127
  svn_boolean_t no_delete_wc = FALSE;
 
2128
  svn_boolean_t file_external;
2176
2129
 
2177
 
  SVN_ERR(svn_wc__db_base_get_info_internal(&status, &kind, NULL,
 
2130
  SVN_ERR(svn_wc__db_base_get_info_internal(&status, &kind, &revision,
2178
2131
                                            &repos_relpath, &repos_id,
2179
2132
                                            NULL, NULL, NULL, NULL, NULL,
2180
 
                                            NULL, NULL, NULL, NULL, NULL,
 
2133
                                            NULL, NULL, NULL, NULL,
 
2134
                                            &file_external,
2181
2135
                                            wcroot, local_relpath,
2182
2136
                                            scratch_pool, scratch_pool));
2183
2137
 
2184
 
  if (remove_locks)
 
2138
  /* Check if there is already a working node */
 
2139
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
2140
                                    STMT_SELECT_NODE_INFO));
 
2141
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
2142
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
2143
 
 
2144
  if (!have_row)
 
2145
    return svn_error_trace(svn_sqlite__reset(stmt)); /* No BASE */
 
2146
 
 
2147
  op_depth = svn_sqlite__column_int(stmt, 0);
 
2148
  wrk_kind = svn_sqlite__column_token(stmt, 4, kind_map);
 
2149
 
 
2150
  if (op_depth > 0
 
2151
      && op_depth == relpath_depth(local_relpath))
2185
2152
    {
2186
 
      svn_sqlite__stmt_t *lock_stmt;
 
2153
      svn_wc__db_status_t presence;
 
2154
      presence = svn_sqlite__column_token(stmt, 3, presence_map);
2187
2155
 
2188
 
      SVN_ERR(svn_sqlite__get_statement(&lock_stmt, wcroot->sdb,
2189
 
                                        STMT_DELETE_LOCK_RECURSIVELY));
2190
 
      SVN_ERR(svn_sqlite__bindf(lock_stmt, "is", repos_id, repos_relpath));
2191
 
      SVN_ERR(svn_sqlite__step_done(lock_stmt));
 
2156
      if (presence == svn_wc__db_status_base_deleted)
 
2157
        {
 
2158
          keep_working = FALSE;
 
2159
          no_delete_wc = TRUE;
 
2160
        }
 
2161
      else
 
2162
        {
 
2163
          keep_working = TRUE;
 
2164
        }
2192
2165
    }
 
2166
  else
 
2167
    keep_working = FALSE;
 
2168
  SVN_ERR(svn_sqlite__reset(stmt));
2193
2169
 
2194
 
  if (status == svn_wc__db_status_normal
2195
 
      && keep_as_working)
 
2170
  if (keep_as_working && op_depth == 0)
2196
2171
    {
2197
 
      SVN_ERR(svn_wc__db_op_make_copy(db,
2198
 
                                      svn_dirent_join(wcroot->abspath,
2199
 
                                                      local_relpath,
2200
 
                                                      scratch_pool),
2201
 
                                      NULL, NULL,
2202
 
                                      scratch_pool));
 
2172
      if (status == svn_wc__db_status_normal
 
2173
          || status == svn_wc__db_status_incomplete)
 
2174
        {
 
2175
          SVN_ERR(svn_wc__db_op_make_copy_internal(wcroot, local_relpath, TRUE,
 
2176
                                                   NULL, NULL,
 
2177
                                                   scratch_pool));
 
2178
        }
2203
2179
      keep_working = TRUE;
2204
2180
    }
2205
 
  else
2206
 
    {
2207
 
      /* Check if there is already a working node */
2208
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
2209
 
                                        STMT_SELECT_WORKING_NODE));
2210
 
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
2211
 
      SVN_ERR(svn_sqlite__step(&keep_working, stmt));
2212
 
      SVN_ERR(svn_sqlite__reset(stmt));
2213
 
    }
2214
2181
 
2215
2182
  /* Step 1: Create workqueue operations to remove files and dirs in the
2216
2183
     local-wc */
2217
 
  if (!keep_working
2218
 
      && queue_deletes
2219
 
      && (status == svn_wc__db_status_normal
2220
 
          || status == svn_wc__db_status_incomplete))
 
2184
  if (!keep_working && !no_delete_wc)
2221
2185
    {
2222
2186
      svn_skel_t *work_item;
2223
2187
      const char *local_abspath;
2224
2188
 
2225
2189
      local_abspath = svn_dirent_join(wcroot->abspath, local_relpath,
2226
2190
                                      scratch_pool);
2227
 
      if (kind == svn_node_dir)
 
2191
      if (wrk_kind == svn_node_dir)
2228
2192
        {
2229
2193
          apr_pool_t *iterpool;
2230
2194
          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
2231
 
                                            STMT_SELECT_BASE_PRESENT));
 
2195
                                            STMT_SELECT_WORKING_PRESENT));
2232
2196
          SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
2233
2197
 
2234
2198
          iterpool = svn_pool_create(scratch_pool);
2307
2271
           ACTUAL_NODE records */
2308
2272
 
2309
2273
  /* Step 3: Delete WORKING nodes */
2310
 
  if (conflict)
 
2274
  if (!keep_working)
2311
2275
    {
2312
2276
      apr_pool_t *iterpool;
2313
2277
 
2314
 
      /*
2315
 
       * When deleting a conflicted node, moves of any moved-outside children
2316
 
       * of the node must be broken. Else, the destination will still be marked
2317
 
       * moved-here after the move source disappears from the working copy.
2318
 
       *
2319
 
       * ### FIXME: It would be nicer to have the conflict resolver
2320
 
       * break the move instead. It might also be a good idea to
2321
 
       * flag a tree conflict on each moved-away child. But doing so
2322
 
       * might introduce actual-only nodes without direct parents,
2323
 
       * and we're not yet sure if other existing code is prepared
2324
 
       * to handle such nodes. To be revisited post-1.8.
2325
 
       *
2326
 
       * ### In case of a conflict we are most likely creating WORKING nodes
2327
 
       *     describing a copy of what was in BASE. The move information
2328
 
       *     should be updated to describe a move from the WORKING layer.
2329
 
       *     When stored that way the resolver of the tree conflict still has
2330
 
       *     the knowledge of what was moved.
 
2278
      /* When deleting everything in working we should break moves from
 
2279
         here and to here.
2331
2280
       */
2332
2281
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
2333
2282
                                        STMT_SELECT_MOVED_OUTSIDE));
2338
2287
      iterpool = svn_pool_create(scratch_pool);
2339
2288
      while (have_row)
2340
2289
        {
2341
 
          const char *child_relpath;
2342
 
          svn_error_t *err;
2343
 
 
2344
 
          svn_pool_clear(iterpool);
2345
 
          child_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
2346
 
          err = clear_moved_here(child_relpath, wcroot, iterpool);
2347
 
          if (err)
2348
 
            return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 
2290
          const char *moved_to_relpath;
 
2291
          svn_error_t *err;
 
2292
 
 
2293
          svn_pool_clear(iterpool);
 
2294
          moved_to_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
 
2295
          err = clear_moved_here(wcroot, moved_to_relpath, iterpool);
 
2296
          if (err)
 
2297
            return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 
2298
          SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
2299
        }
 
2300
      svn_pool_destroy(iterpool);
 
2301
      SVN_ERR(svn_sqlite__reset(stmt));
 
2302
    }
 
2303
  else
 
2304
    {
 
2305
      /* We are keeping things that are in WORKING, but we should still
 
2306
         break moves of things in BASE. (Mixed revisions make it
 
2307
         impossible to guarantee that we can keep everything moved) */
 
2308
 
 
2309
      apr_pool_t *iterpool;
 
2310
 
 
2311
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
2312
                                        STMT_SELECT_MOVED_DESCENDANTS_SRC));
 
2313
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
 
2314
                                local_relpath, 0));
 
2315
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
2316
      iterpool = svn_pool_create(scratch_pool);
 
2317
      while (have_row)
 
2318
        {
 
2319
          int delete_op_depth = svn_sqlite__column_int(stmt, 0);
 
2320
          const char *src_relpath;
 
2321
          const char *dst_relpath;
 
2322
          svn_error_t *err;
 
2323
 
 
2324
          svn_pool_clear(iterpool);
 
2325
 
 
2326
          src_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
 
2327
          dst_relpath = svn_sqlite__column_text(stmt, 4, iterpool);
 
2328
 
 
2329
          err = svn_wc__db_op_break_move_internal(wcroot, src_relpath,
 
2330
                                                  delete_op_depth,
 
2331
                                                  dst_relpath,
 
2332
                                                  NULL,
 
2333
                                                  iterpool);
 
2334
 
 
2335
          if (err)
 
2336
            return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 
2337
 
2349
2338
          SVN_ERR(svn_sqlite__step(&have_row, stmt));
2350
2339
        }
2351
2340
      svn_pool_destroy(iterpool);
2353
2342
    }
2354
2343
  if (keep_working)
2355
2344
    {
2356
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
2357
 
                                        STMT_DELETE_WORKING_BASE_DELETE));
2358
 
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
2345
      SVN_ERR(svn_sqlite__get_statement(
 
2346
                    &stmt, wcroot->sdb,
 
2347
                    STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE));
 
2348
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0));
2359
2349
      SVN_ERR(svn_sqlite__step_done(stmt));
2360
2350
    }
2361
2351
  else
2372
2362
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
2373
2363
  SVN_ERR(svn_sqlite__step_done(stmt));
2374
2364
 
2375
 
  /* Step 5: handle the BASE node itself */
2376
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
2377
 
                                    STMT_DELETE_BASE_NODE));
2378
 
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
2379
 
  SVN_ERR(svn_sqlite__step_done(stmt));
2380
 
 
2381
 
  SVN_ERR(svn_wc__db_retract_parent_delete(wcroot, local_relpath, 0,
2382
 
                                           scratch_pool));
2383
 
 
2384
 
  /* Step 6: Delete actual node if we don't keep working */
2385
 
  if (! keep_working)
2386
 
    {
2387
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
2388
 
                                        STMT_DELETE_ACTUAL_NODE));
2389
 
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
2390
 
      SVN_ERR(svn_sqlite__step_done(stmt));
2391
 
    }
2392
 
 
2393
 
  if (SVN_IS_VALID_REVNUM(not_present_revision))
 
2365
  SVN_ERR(db_retract_parent_delete(wcroot, local_relpath, 0, scratch_pool));
 
2366
 
 
2367
  if (mark_not_present || mark_excluded)
2394
2368
    {
2395
2369
      struct insert_base_baton_t ibb;
2396
 
      blank_ibb(&ibb);
2397
 
 
2398
 
      ibb.repos_id = repos_id;
2399
 
      ibb.status = svn_wc__db_status_not_present;
2400
 
      ibb.kind = kind;
2401
 
      ibb.repos_relpath = repos_relpath;
2402
 
      ibb.revision = not_present_revision;
2403
 
 
2404
 
      /* Depending upon KIND, any of these might get used. */
2405
 
      ibb.children = NULL;
2406
 
      ibb.depth = svn_depth_unknown;
2407
 
      ibb.checksum = NULL;
2408
 
      ibb.target = NULL;
2409
 
 
2410
 
      SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
 
2370
      svn_boolean_t no_marker = FALSE;
 
2371
 
 
2372
      if (file_external)
 
2373
        {
 
2374
          const char *parent_local_relpath;
 
2375
          const char *name;
 
2376
          svn_error_t *err;
 
2377
 
 
2378
          /* For file externals we only want to place a not present marker
 
2379
             if there is a BASE parent */
 
2380
          
 
2381
          svn_relpath_split(&parent_local_relpath, &name, local_relpath,
 
2382
                            scratch_pool);
 
2383
 
 
2384
          err = svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
 
2385
                                                  &repos_relpath, &repos_id,
 
2386
                                                  NULL, NULL, NULL, NULL, NULL,
 
2387
                                                  NULL, NULL, NULL, NULL, NULL,
 
2388
                                                  wcroot, parent_local_relpath,
 
2389
                                                  scratch_pool, scratch_pool);
 
2390
 
 
2391
          if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
 
2392
            return svn_error_trace(err);
 
2393
          else if (err)
 
2394
            {
 
2395
              svn_error_clear(err);
 
2396
              no_marker = TRUE;
 
2397
            }
 
2398
          else
 
2399
            {
 
2400
              /* Replace the repos_relpath with something more expected than
 
2401
                 the unrelated old file external repository relpath, which
 
2402
                 one day may come from a different repository */
 
2403
              repos_relpath = svn_relpath_join(repos_relpath, name, scratch_pool);
 
2404
            }
 
2405
        }
 
2406
 
 
2407
      if (!no_marker)
 
2408
        {
 
2409
          blank_ibb(&ibb);
 
2410
 
 
2411
          ibb.repos_id = repos_id;
 
2412
          ibb.status = mark_excluded ? svn_wc__db_status_excluded
 
2413
                                     : svn_wc__db_status_not_present;
 
2414
          ibb.kind = kind;
 
2415
          ibb.repos_relpath = repos_relpath;
 
2416
          ibb.revision = SVN_IS_VALID_REVNUM(marker_revision)
 
2417
                            ? marker_revision
 
2418
                            : revision;
 
2419
 
 
2420
          /* Depending upon KIND, any of these might get used. */
 
2421
          ibb.children = NULL;
 
2422
          ibb.depth = svn_depth_unknown;
 
2423
          ibb.checksum = NULL;
 
2424
          ibb.target = NULL;
 
2425
 
 
2426
          SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
 
2427
        }
2411
2428
    }
2412
2429
 
2413
2430
  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
2423
2440
svn_wc__db_base_remove(svn_wc__db_t *db,
2424
2441
                       const char *local_abspath,
2425
2442
                       svn_boolean_t keep_as_working,
2426
 
                       svn_boolean_t queue_deletes,
2427
 
                       svn_boolean_t remove_locks,
2428
 
                       svn_revnum_t not_present_revision,
 
2443
                       svn_boolean_t mark_not_present,
 
2444
                       svn_boolean_t mark_excluded,
 
2445
                       svn_revnum_t marker_revision,
2429
2446
                       svn_skel_t *conflict,
2430
2447
                       svn_skel_t *work_items,
2431
2448
                       apr_pool_t *scratch_pool)
2440
2457
  VERIFY_USABLE_WCROOT(wcroot);
2441
2458
 
2442
2459
  SVN_WC__DB_WITH_TXN(db_base_remove(wcroot, local_relpath,
2443
 
                                     db, keep_as_working, queue_deletes,
2444
 
                                     remove_locks, not_present_revision,
 
2460
                                     db, keep_as_working,
 
2461
                                     mark_not_present, mark_excluded,
 
2462
                                     marker_revision,
2445
2463
                                     conflict, work_items, scratch_pool),
2446
2464
                      wcroot);
2447
2465
 
2638
2656
                                            wcroot, local_relpath,
2639
2657
                                            result_pool, scratch_pool),
2640
2658
          svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
2641
 
                                      wcroot->sdb, repos_id, result_pool),
 
2659
                                      wcroot, repos_id, result_pool),
2642
2660
          SVN_NO_ERROR,
2643
2661
          SVN_NO_ERROR,
2644
2662
          wcroot);
2647
2665
  return SVN_NO_ERROR;
2648
2666
}
2649
2667
 
2650
 
svn_error_t *
2651
 
svn_wc__db_base_get_children_info(apr_hash_t **nodes,
2652
 
                                  svn_wc__db_t *db,
2653
 
                                  const char *dir_abspath,
2654
 
                                  apr_pool_t *result_pool,
2655
 
                                  apr_pool_t *scratch_pool)
 
2668
/* The implementation of svn_wc__db_base_get_children_info */
 
2669
static svn_error_t *
 
2670
base_get_children_info(apr_hash_t **nodes,
 
2671
                       svn_wc__db_wcroot_t *wcroot,
 
2672
                       const char *local_relpath,
 
2673
                       svn_boolean_t obtain_locks,
 
2674
                       apr_pool_t *result_pool,
 
2675
                       apr_pool_t *scratch_pool)
2656
2676
{
2657
 
  svn_wc__db_wcroot_t *wcroot;
2658
 
  const char *local_relpath;
2659
2677
  svn_sqlite__stmt_t *stmt;
2660
2678
  svn_boolean_t have_row;
2661
 
 
2662
 
  SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
2663
 
 
2664
 
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
2665
 
                              dir_abspath, scratch_pool, scratch_pool));
2666
 
  VERIFY_USABLE_WCROOT(wcroot);
 
2679
  apr_int64_t last_repos_id = INVALID_REPOS_ID;
 
2680
  const char *last_repos_root_url = NULL;
2667
2681
 
2668
2682
  *nodes = apr_hash_make(result_pool);
2669
2683
 
2670
2684
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
2671
 
                                    STMT_SELECT_BASE_CHILDREN_INFO));
 
2685
                                    obtain_locks
 
2686
                                      ? STMT_SELECT_BASE_CHILDREN_INFO_LOCK
 
2687
                                      : STMT_SELECT_BASE_CHILDREN_INFO));
2672
2688
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
2673
2689
 
2674
2690
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
2676
2692
  while (have_row)
2677
2693
    {
2678
2694
      struct svn_wc__db_base_info_t *info;
2679
 
      svn_error_t *err;
2680
2695
      apr_int64_t repos_id;
2681
2696
      const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
2682
2697
      const char *name = svn_relpath_basename(child_relpath, result_pool);
2694
2709
 
2695
2710
      info->update_root = svn_sqlite__column_boolean(stmt, 7);
2696
2711
 
2697
 
      info->lock = lock_from_columns(stmt, 8, 9, 10, 11, result_pool);
2698
 
 
2699
 
      err = svn_wc__db_fetch_repos_info(&info->repos_root_url, NULL,
2700
 
                                        wcroot->sdb, repos_id, result_pool);
2701
 
 
2702
 
      if (err)
2703
 
        return svn_error_trace(
2704
 
                 svn_error_compose_create(err,
2705
 
                                          svn_sqlite__reset(stmt)));
2706
 
 
 
2712
      if (obtain_locks)
 
2713
        info->lock = lock_from_columns(stmt, 8, 9, 10, 11, result_pool);
 
2714
 
 
2715
      if (repos_id != last_repos_id)
 
2716
        {
 
2717
          svn_error_t *err;
 
2718
 
 
2719
          err = svn_wc__db_fetch_repos_info(&last_repos_root_url, NULL,
 
2720
                                            wcroot, repos_id,
 
2721
                                            result_pool);
 
2722
 
 
2723
          if (err)
 
2724
            return svn_error_trace(
 
2725
                     svn_error_compose_create(err,
 
2726
                                              svn_sqlite__reset(stmt)));
 
2727
 
 
2728
          last_repos_id = repos_id;
 
2729
        }
 
2730
 
 
2731
      info->repos_root_url = last_repos_root_url;
2707
2732
 
2708
2733
      svn_hash_sets(*nodes, name, info);
2709
2734
 
2715
2740
  return SVN_NO_ERROR;
2716
2741
}
2717
2742
 
 
2743
svn_error_t *
 
2744
svn_wc__db_base_get_children_info(apr_hash_t **nodes,
 
2745
                                  svn_wc__db_t *db,
 
2746
                                  const char *dir_abspath,
 
2747
                                  apr_pool_t *result_pool,
 
2748
                                  apr_pool_t *scratch_pool)
 
2749
{
 
2750
  svn_wc__db_wcroot_t *wcroot;
 
2751
  const char *local_relpath;
 
2752
 
 
2753
  SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
 
2754
 
 
2755
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
 
2756
                              dir_abspath, scratch_pool, scratch_pool));
 
2757
  VERIFY_USABLE_WCROOT(wcroot);
 
2758
 
 
2759
  return svn_error_trace(base_get_children_info(nodes,
 
2760
                                                wcroot,
 
2761
                                                local_relpath,
 
2762
                                                TRUE /* obtain_locks */,
 
2763
                                                result_pool,
 
2764
                                                scratch_pool));
 
2765
}
 
2766
 
2718
2767
 
2719
2768
svn_error_t *
2720
2769
svn_wc__db_base_get_props(apr_hash_t **props,
2761
2810
                                             scratch_pool, scratch_pool));
2762
2811
  VERIFY_USABLE_WCROOT(wcroot);
2763
2812
 
2764
 
  return gather_repo_children(children, wcroot, local_relpath, 0,
2765
 
                              result_pool, scratch_pool);
 
2813
  return svn_error_trace(
 
2814
              gather_children(children, wcroot, local_relpath,
 
2815
                              STMT_SELECT_OP_DEPTH_CHILDREN, 0,
 
2816
                              result_pool, scratch_pool));
2766
2817
}
2767
2818
 
2768
2819
 
2772
2823
                              const apr_hash_t *props,
2773
2824
                              apr_pool_t *scratch_pool)
2774
2825
{
 
2826
  svn_wc__db_wcroot_t *wcroot;
 
2827
  const char *local_relpath;
2775
2828
  svn_sqlite__stmt_t *stmt;
2776
2829
  int affected_rows;
2777
2830
 
2778
 
  SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
2779
 
                                 STMT_UPDATE_BASE_NODE_DAV_CACHE,
2780
 
                                 scratch_pool));
 
2831
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
2832
 
 
2833
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
 
2834
                              local_abspath, scratch_pool, scratch_pool));
 
2835
  VERIFY_USABLE_WCROOT(wcroot);
 
2836
 
 
2837
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
2838
                                    STMT_UPDATE_BASE_NODE_DAV_CACHE));
 
2839
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
2781
2840
  SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
2782
2841
 
2783
2842
  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
2799
2858
                              apr_pool_t *result_pool,
2800
2859
                              apr_pool_t *scratch_pool)
2801
2860
{
 
2861
  svn_wc__db_wcroot_t *wcroot;
 
2862
  const char *local_relpath;
2802
2863
  svn_sqlite__stmt_t *stmt;
2803
2864
  svn_boolean_t have_row;
2804
2865
 
2805
 
  SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
2806
 
                                 STMT_SELECT_BASE_DAV_CACHE, scratch_pool));
 
2866
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
2867
 
 
2868
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
 
2869
                              local_abspath, scratch_pool, scratch_pool));
 
2870
  VERIFY_USABLE_WCROOT(wcroot);
 
2871
 
 
2872
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
2873
                                    STMT_SELECT_BASE_DAV_CACHE));
 
2874
 
2807
2875
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
2808
2876
  if (!have_row)
2809
2877
    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
2944
3012
        }
2945
3013
      if (had_props)
2946
3014
        {
2947
 
          *had_props = SQLITE_PROPERTIES_AVAILABLE(stmt, 13);
 
3015
          *had_props = SQLITE_PROPERTIES_AVAILABLE(stmt, 12);
2948
3016
        }
2949
3017
      if (props)
2950
3018
        {
2951
3019
          if (node_status == svn_wc__db_status_normal
2952
3020
              || node_status == svn_wc__db_status_incomplete)
2953
3021
            {
2954
 
              SVN_ERR(svn_sqlite__column_properties(props, stmt, 13,
 
3022
              SVN_ERR(svn_sqlite__column_properties(props, stmt, 12,
2955
3023
                                                    result_pool, scratch_pool));
2956
3024
              if (*props == NULL)
2957
3025
                *props = apr_hash_make(result_pool);
2958
3026
            }
2959
3027
          else
2960
3028
            {
2961
 
              assert(svn_sqlite__column_is_null(stmt, 13));
 
3029
              assert(svn_sqlite__column_is_null(stmt, 12));
2962
3030
              *props = NULL;
2963
3031
            }
2964
3032
        }
2975
3043
  return svn_error_compose_create(err, svn_sqlite__reset(stmt));
2976
3044
}
2977
3045
 
 
3046
/* A callback which supplies WCROOTs and LOCAL_RELPATHs. */
 
3047
typedef svn_error_t *(*svn_wc__db_txn_callback_t)(void *baton,
 
3048
                                          svn_wc__db_wcroot_t *wcroot,
 
3049
                                          const char *local_relpath,
 
3050
                                          apr_pool_t *scratch_pool);
2978
3051
 
2979
3052
/* Baton for passing args to with_triggers(). */
2980
3053
struct with_triggers_baton_t {
3051
3124
  svn_error_t *err1;
3052
3125
  svn_error_t *err2;
3053
3126
 
3054
 
  err1 = svn_wc__db_with_txn(wcroot, local_relpath, txn_cb, txn_baton,
3055
 
                             scratch_pool);
 
3127
  err1 = svn_sqlite__begin_savepoint(wcroot->sdb);
 
3128
  if (!err1)
 
3129
    {
 
3130
      err1 = txn_cb(txn_baton, wcroot, local_relpath, scratch_pool);
 
3131
 
 
3132
      err1 = svn_sqlite__finish_savepoint(wcroot->sdb, err1);
 
3133
    }
3056
3134
 
3057
3135
  if (err1 == NULL && notify_func != NULL)
3058
3136
    {
3438
3516
                   apr_pool_t *scratch_pool)
3439
3517
{
3440
3518
  svn_sqlite__stmt_t *stmt;
 
3519
  int affected_rows;
3441
3520
 
3442
3521
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
3443
3522
                                    STMT_DELETE_EXTERNAL));
3444
3523
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
3445
 
  SVN_ERR(svn_sqlite__step_done(stmt));
 
3524
  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
3525
 
 
3526
  if (!affected_rows)
 
3527
    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
 
3528
                             _("The node '%s' is not an external."),
 
3529
                             path_for_error_message(wcroot, local_relpath,
 
3530
                                                    scratch_pool));
3446
3531
 
3447
3532
  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
3448
3533
 
3543
3628
          err = svn_error_compose_create(
3544
3629
                        err,
3545
3630
                        svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
3546
 
                                                    wcroot->sdb, repos_id,
 
3631
                                                    wcroot, repos_id,
3547
3632
                                                    result_pool));
3548
3633
        }
3549
3634
 
3925
4010
/* The body of svn_wc__db_scan_deletion().
3926
4011
 */
3927
4012
static svn_error_t *
3928
 
scan_deletion_txn(const char **base_del_relpath,
3929
 
                  const char **moved_to_relpath,
3930
 
                  const char **work_del_relpath,
3931
 
                  const char **moved_to_op_root_relpath,
3932
 
                  svn_wc__db_wcroot_t *wcroot,
3933
 
                  const char *local_relpath,
3934
 
                  apr_pool_t *result_pool,
3935
 
                  apr_pool_t *scratch_pool)
 
4013
scan_deletion(const char **base_del_relpath,
 
4014
              const char **moved_to_relpath,
 
4015
              const char **work_del_relpath,
 
4016
              const char **moved_to_op_root_relpath,
 
4017
              svn_wc__db_wcroot_t *wcroot,
 
4018
              const char *local_relpath,
 
4019
              apr_pool_t *result_pool,
 
4020
              apr_pool_t *scratch_pool)
3936
4021
{
3937
4022
  const char *current_relpath = local_relpath;
3938
4023
  svn_sqlite__stmt_t *stmt;
3956
4041
  scan = (moved_to_op_root_relpath || moved_to_relpath);
3957
4042
 
3958
4043
  SVN_ERR(svn_sqlite__get_statement(
3959
 
                    &stmt, wcroot->sdb,
3960
 
                    scan ? STMT_SELECT_DELETION_INFO_SCAN
3961
 
                         : STMT_SELECT_DELETION_INFO));
 
4044
                    &stmt, wcroot->sdb, STMT_SELECT_DELETION_INFO));
3962
4045
 
3963
4046
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
3964
4047
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
4079
4162
}
4080
4163
 
4081
4164
svn_error_t *
 
4165
svn_wc__db_scan_deletion_internal(
 
4166
              const char **base_del_relpath,
 
4167
              const char **moved_to_relpath,
 
4168
              const char **work_del_relpath,
 
4169
              const char **moved_to_op_root_relpath,
 
4170
              svn_wc__db_wcroot_t *wcroot,
 
4171
              const char *local_relpath,
 
4172
              apr_pool_t *result_pool,
 
4173
              apr_pool_t *scratch_pool)
 
4174
{
 
4175
  return svn_error_trace(
 
4176
            scan_deletion(base_del_relpath, moved_to_relpath, work_del_relpath,
 
4177
                          moved_to_op_root_relpath,
 
4178
                          wcroot, local_relpath,
 
4179
                          result_pool, scratch_pool));
 
4180
}
 
4181
 
 
4182
 
 
4183
svn_error_t *
4082
4184
svn_wc__db_scan_deletion(const char **base_del_abspath,
4083
4185
                         const char **moved_to_abspath,
4084
4186
                         const char **work_del_abspath,
4100
4202
  VERIFY_USABLE_WCROOT(wcroot);
4101
4203
 
4102
4204
  SVN_WC__DB_WITH_TXN(
4103
 
    scan_deletion_txn(&base_del_relpath, &moved_to_relpath,
4104
 
                      &work_del_relpath, &moved_to_op_root_relpath,
4105
 
                      wcroot, local_relpath, result_pool, scratch_pool),
 
4205
    scan_deletion(&base_del_relpath, &moved_to_relpath,
 
4206
                  &work_del_relpath, &moved_to_op_root_relpath,
 
4207
                  wcroot, local_relpath, result_pool, scratch_pool),
4106
4208
    wcroot);
4107
4209
 
4108
4210
  if (base_del_abspath)
4200
4302
    {
4201
4303
      const char *base_del_relpath, *work_del_relpath;
4202
4304
 
4203
 
      SVN_ERR(scan_deletion_txn(&base_del_relpath, NULL,
4204
 
                                &work_del_relpath,
4205
 
                                NULL, src_wcroot, local_relpath,
4206
 
                                scratch_pool, scratch_pool));
 
4305
      SVN_ERR(scan_deletion(&base_del_relpath, NULL,
 
4306
                            &work_del_relpath,
 
4307
                            NULL, src_wcroot, local_relpath,
 
4308
                            scratch_pool, scratch_pool));
4207
4309
      if (work_del_relpath)
4208
4310
        {
4209
4311
          const char *op_root_relpath;
4264
4366
         working copies in a single db)! */
4265
4367
 
4266
4368
      SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, &repos_uuid,
4267
 
                                          src_wcroot->sdb, *copyfrom_id,
 
4369
                                          src_wcroot, *copyfrom_id,
4268
4370
                                          scratch_pool));
4269
4371
 
4270
4372
      SVN_ERR(create_repos_id(copyfrom_id, repos_root_url, repos_uuid,
4532
4634
      int src_op_depth;
4533
4635
 
4534
4636
      SVN_ERR(op_depth_of(&src_op_depth, src_wcroot, src_relpath));
4535
 
      SVN_ERR(gather_repo_children(&children, src_wcroot, src_relpath,
4536
 
                                   src_op_depth, scratch_pool, scratch_pool));
 
4637
      SVN_ERR(gather_children(&children, src_wcroot, src_relpath,
 
4638
                              STMT_SELECT_OP_DEPTH_CHILDREN, src_op_depth,
 
4639
                              scratch_pool, scratch_pool));
4537
4640
    }
4538
4641
  else
4539
4642
    children = NULL;
4684
4787
  const char *dst_op_root_relpath;
4685
4788
};
4686
4789
 
4687
 
/* Helper for svn_wc__db_op_copy().
4688
 
 *
4689
 
 * Implements svn_sqlite__transaction_callback_t. */
 
4790
/* Helper for svn_wc__db_op_copy(). */
4690
4791
static svn_error_t *
4691
 
op_copy_txn(void * baton,
4692
 
            svn_sqlite__db_t *sdb,
 
4792
op_copy_txn(svn_wc__db_wcroot_t *wcroot,
 
4793
            struct op_copy_baton *ocb,
4693
4794
            apr_pool_t *scratch_pool)
4694
4795
{
4695
 
  struct op_copy_baton *ocb = baton;
4696
4796
  int move_op_depth;
4697
4797
 
4698
 
  if (sdb != ocb->dst_wcroot->sdb)
 
4798
  if (wcroot != ocb->dst_wcroot)
4699
4799
    {
4700
4800
       /* Source and destination databases differ; so also start a lock
4701
 
          in the destination database, by calling ourself in a lock. */
4702
 
 
4703
 
      return svn_error_trace(
4704
 
                        svn_sqlite__with_lock(ocb->dst_wcroot->sdb,
4705
 
                                              op_copy_txn, ocb, scratch_pool));
 
4801
          in the destination database, by calling ourself in an extra lock. */
 
4802
 
 
4803
      SVN_WC__DB_WITH_TXN(op_copy_txn(ocb->dst_wcroot, ocb, scratch_pool),
 
4804
                          ocb->dst_wcroot);
 
4805
 
 
4806
      return SVN_NO_ERROR;
4706
4807
    }
4707
4808
 
4708
4809
  /* From this point we can assume a lock in the src and dst databases */
4753
4854
 
4754
4855
  /* Call with the sdb in src_wcroot. It might call itself again to
4755
4856
     also obtain a lock in dst_wcroot */
4756
 
  SVN_ERR(svn_sqlite__with_lock(ocb.src_wcroot->sdb, op_copy_txn, &ocb,
4757
 
                                scratch_pool));
 
4857
  SVN_WC__DB_WITH_TXN(op_copy_txn(ocb.src_wcroot, &ocb, scratch_pool),
 
4858
                      ocb.src_wcroot);
 
4859
 
 
4860
  return SVN_NO_ERROR;
 
4861
}
 
4862
 
 
4863
/* Remove unneeded actual nodes for svn_wc__db_op_copy_layer_internal */
 
4864
static svn_error_t *
 
4865
clear_or_remove_actual(svn_wc__db_wcroot_t *wcroot,
 
4866
                       const char *local_relpath,
 
4867
                       int op_depth,
 
4868
                       apr_pool_t *scratch_pool)
 
4869
{
 
4870
  svn_sqlite__stmt_t *stmt;
 
4871
  svn_boolean_t have_row, shadowed;
 
4872
  svn_boolean_t keep_conflict = FALSE;
 
4873
 
 
4874
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
4875
                                    STMT_SELECT_NODE_INFO));
 
4876
 
 
4877
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
4878
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
4879
 
 
4880
  if (have_row)
 
4881
    {
 
4882
      svn_wc__db_status_t presence;
 
4883
 
 
4884
      shadowed = (svn_sqlite__column_int(stmt, 0) > op_depth);
 
4885
      presence = svn_sqlite__column_token(stmt, 3, presence_map);
 
4886
 
 
4887
      if (shadowed && presence == svn_wc__db_status_base_deleted)
 
4888
        {
 
4889
          keep_conflict = TRUE;
 
4890
          SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
4891
 
 
4892
          if (have_row)
 
4893
            shadowed = (svn_sqlite__column_int(stmt, 0) > op_depth);
 
4894
          else
 
4895
            shadowed = FALSE;
 
4896
        }
 
4897
    }
 
4898
  else
 
4899
    shadowed = FALSE;
 
4900
 
 
4901
  SVN_ERR(svn_sqlite__reset(stmt));
 
4902
  if (shadowed)
 
4903
    return SVN_NO_ERROR;
 
4904
 
 
4905
  if (keep_conflict)
 
4906
    {
 
4907
      /* We don't want to accidentally remove delete-delete conflicts */
 
4908
      SVN_ERR(svn_sqlite__get_statement(
 
4909
                          &stmt, wcroot->sdb,
 
4910
                          STMT_CLEAR_ACTUAL_NODE_LEAVING_CONFLICT));
 
4911
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
4912
      SVN_ERR(svn_sqlite__step_done(stmt));
 
4913
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
4914
                                        STMT_DELETE_ACTUAL_EMPTY));
 
4915
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
4916
      SVN_ERR(svn_sqlite__step_done(stmt));
 
4917
    }
 
4918
  else
 
4919
    {
 
4920
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
4921
                                        STMT_DELETE_ACTUAL_NODE));
 
4922
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
4923
      SVN_ERR(svn_sqlite__step_done(stmt));
 
4924
    }
 
4925
 
 
4926
  return SVN_NO_ERROR;
 
4927
}
 
4928
 
 
4929
svn_error_t *
 
4930
svn_wc__db_op_copy_layer_internal(svn_wc__db_wcroot_t *wcroot,
 
4931
                                  const char *src_op_relpath,
 
4932
                                  int src_op_depth,
 
4933
                                  const char *dst_op_relpath,
 
4934
                                  svn_skel_t *conflict,
 
4935
                                  svn_skel_t *work_items,
 
4936
                                  apr_pool_t *scratch_pool)
 
4937
{
 
4938
  svn_sqlite__stmt_t *stmt, *stmt2;
 
4939
  svn_boolean_t have_row;
 
4940
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
4941
  int dst_op_depth = relpath_depth(dst_op_relpath);
 
4942
  svn_boolean_t locked;
 
4943
  svn_error_t *err = NULL;
 
4944
 
 
4945
  SVN_ERR(svn_wc__db_wclock_owns_lock_internal(&locked, wcroot, dst_op_relpath,
 
4946
                                               FALSE, scratch_pool));
 
4947
 
 
4948
  if (!locked)
 
4949
    return svn_error_createf(SVN_ERR_WC_NOT_LOCKED, NULL,
 
4950
                             _("No write-lock in '%s'"),
 
4951
                             path_for_error_message(wcroot, dst_op_relpath,
 
4952
                                                    scratch_pool));
 
4953
 
 
4954
  SVN_ERR(svn_sqlite__get_statement(&stmt2, wcroot->sdb,
 
4955
                                    STMT_COPY_NODE_MOVE));
 
4956
 
 
4957
  /* Replace entire subtree at one op-depth. */
 
4958
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
4959
                                    STMT_SELECT_LAYER_FOR_REPLACE));
 
4960
  SVN_ERR(svn_sqlite__bindf(stmt, "isdsd", wcroot->wc_id,
 
4961
                            src_op_relpath, src_op_depth,
 
4962
                            dst_op_relpath, dst_op_depth));
 
4963
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
4964
  while (have_row)
 
4965
    {
 
4966
      const char *src_relpath;
 
4967
      const char *dst_relpath;
 
4968
 
 
4969
      svn_pool_clear(iterpool);
 
4970
 
 
4971
      src_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
 
4972
      dst_relpath = svn_sqlite__column_text(stmt, 2, iterpool);
 
4973
 
 
4974
      err = svn_sqlite__bindf(stmt2, "isdsds", wcroot->wc_id,
 
4975
                              src_relpath, src_op_depth,
 
4976
                              dst_relpath, dst_op_depth,
 
4977
                              svn_relpath_dirname(dst_relpath, iterpool));
 
4978
      if (!err)
 
4979
        err = svn_sqlite__step_done(stmt2);
 
4980
 
 
4981
      /* stmt2 is reset (never modified or by step_done) */
 
4982
 
 
4983
      if (err)
 
4984
        break;
 
4985
 
 
4986
      /* The node can't be deleted where it is added, so extension of
 
4987
         an existing shadowing is only interesting 2 levels deep. */
 
4988
      if (relpath_depth(dst_relpath) > (dst_op_depth+1))
 
4989
        {
 
4990
          svn_boolean_t exists = !svn_sqlite__column_is_null(stmt, 3);
 
4991
 
 
4992
          if (exists)
 
4993
            {
 
4994
              svn_wc__db_status_t presence;
 
4995
 
 
4996
              presence = svn_sqlite__column_token(stmt, 3, presence_map);
 
4997
 
 
4998
              if (presence != svn_wc__db_status_normal)
 
4999
                exists = FALSE;
 
5000
            }
 
5001
 
 
5002
          if (!exists)
 
5003
            {
 
5004
              svn_node_kind_t kind = svn_sqlite__column_token(stmt, 1, kind_map);
 
5005
 
 
5006
              err = db_extend_parent_delete(wcroot, dst_relpath,
 
5007
                                            kind, dst_op_depth, iterpool);
 
5008
 
 
5009
              if (err)
 
5010
                break;
 
5011
            }
 
5012
        }
 
5013
 
 
5014
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
5015
    }
 
5016
 
 
5017
  SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
 
5018
 
 
5019
  /* And now remove the records that are no longer needed */
 
5020
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
5021
                                    STMT_SELECT_NO_LONGER_MOVED_RV));
 
5022
  SVN_ERR(svn_sqlite__bindf(stmt, "isdsd", wcroot->wc_id,
 
5023
                            dst_op_relpath, dst_op_depth,
 
5024
                            src_op_relpath, src_op_depth));
 
5025
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
5026
  while (have_row)
 
5027
    {
 
5028
      const char *dst_relpath;
 
5029
      svn_wc__db_status_t shadowed_presence;
 
5030
 
 
5031
      svn_pool_clear(iterpool);
 
5032
 
 
5033
      dst_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
 
5034
 
 
5035
      if (!svn_sqlite__column_is_null(stmt, 2))
 
5036
        shadowed_presence = svn_sqlite__column_token(stmt, 2, presence_map);
 
5037
      else
 
5038
        shadowed_presence = svn_wc__db_status_not_present;
 
5039
 
 
5040
      if (shadowed_presence != svn_wc__db_status_normal
 
5041
          && shadowed_presence != svn_wc__db_status_incomplete)
 
5042
        {
 
5043
          err = svn_sqlite__get_statement(&stmt2, wcroot->sdb,
 
5044
                                            STMT_DELETE_NODE);
 
5045
        }
 
5046
      else
 
5047
        {
 
5048
          err =svn_sqlite__get_statement(&stmt2, wcroot->sdb,
 
5049
                                         STMT_REPLACE_WITH_BASE_DELETED);
 
5050
        }
 
5051
 
 
5052
      if (!err)
 
5053
        err = svn_sqlite__bindf(stmt2, "isd", wcroot->wc_id, dst_relpath,
 
5054
                                             dst_op_depth);
 
5055
 
 
5056
      if (!err)
 
5057
        err = svn_sqlite__step_done(stmt2);
 
5058
 
 
5059
      /* stmt2 is reset (never modified or by step_done) */
 
5060
      if (err)
 
5061
        break;
 
5062
 
 
5063
      /* Delete ACTUAL information about this node that we just deleted */
 
5064
      err = clear_or_remove_actual(wcroot, dst_relpath, dst_op_depth,
 
5065
                                   scratch_pool);
 
5066
 
 
5067
      if (err)
 
5068
        break;
 
5069
 
 
5070
      /* Retract base-delete for the node itself */
 
5071
      err = db_retract_parent_delete(wcroot, dst_relpath, dst_op_depth,
 
5072
                                     scratch_pool);
 
5073
 
 
5074
      if (err)
 
5075
        break;
 
5076
 
 
5077
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
5078
    }
 
5079
  svn_pool_destroy(iterpool);
 
5080
 
 
5081
  SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
 
5082
 
 
5083
  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
 
5084
 
 
5085
  if (conflict)
 
5086
    SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, dst_op_relpath /* ## */,
 
5087
                                              conflict, scratch_pool));
4758
5088
 
4759
5089
  return SVN_NO_ERROR;
4760
5090
}
4919
5249
             generally these values should be the same anyway as it was
4920
5250
             a no-op move. */
4921
5251
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
4922
 
                                        STMT_DELETE_MOVED_BACK));
 
5252
                                        STMT_DELETE_WORKING_OP_DEPTH));
4923
5253
 
4924
5254
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
4925
5255
                                             local_relpath,
5044
5374
          const char *repos_uuid;
5045
5375
 
5046
5376
          SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, &repos_uuid,
5047
 
                                              src_wcroot->sdb, node_repos_id,
 
5377
                                              src_wcroot, node_repos_id,
5048
5378
                                              scratch_pool));
5049
5379
 
5050
5380
          SVN_ERR(create_repos_id(&node_repos_id, repos_root_url, repos_uuid,
5166
5496
      return SVN_NO_ERROR;
5167
5497
    }
5168
5498
 
5169
 
  SVN_ERR(gather_repo_children(&children, src_wcroot, src_relpath,
5170
 
                               src_op_depth, scratch_pool, iterpool));
 
5499
  SVN_ERR(gather_children(&children, src_wcroot, src_relpath,
 
5500
                          STMT_SELECT_OP_DEPTH_CHILDREN, src_op_depth,
 
5501
                          scratch_pool, iterpool));
5171
5502
 
5172
5503
  for (i = 0; i < children->nelts; i++)
5173
5504
    {
5196
5527
  return SVN_NO_ERROR;
5197
5528
}
5198
5529
 
5199
 
/* Helper for svn_wc__db_op_copy_shadowed_layer().
5200
 
 *
5201
 
 * Implements  svn_sqlite__transaction_callback_t. */
 
5530
/* Helper for svn_wc__db_op_copy_shadowed_layer(). */
5202
5531
static svn_error_t *
5203
 
op_copy_shadowed_layer_txn(void *baton,
5204
 
                           svn_sqlite__db_t *sdb,
 
5532
op_copy_shadowed_layer_txn(svn_wc__db_wcroot_t *wcroot,
 
5533
                           struct op_copy_baton *ocb,
5205
5534
                           apr_pool_t *scratch_pool)
5206
5535
{
5207
 
  struct op_copy_baton *ocb = baton;
5208
5536
  const char *src_parent_relpath;
5209
5537
  const char *dst_parent_relpath;
5210
5538
  int src_op_depth;
5214
5542
  apr_int64_t repos_id = INVALID_REPOS_ID;
5215
5543
  svn_revnum_t revision = SVN_INVALID_REVNUM;
5216
5544
 
5217
 
  if (sdb != ocb->dst_wcroot->sdb)
 
5545
  if (wcroot != ocb->dst_wcroot)
5218
5546
    {
5219
 
       /* Source and destination databases differ; so also start a lock
5220
 
          in the destination database, by calling ourself in a lock. */
5221
 
 
5222
 
      return svn_error_trace(
5223
 
                        svn_sqlite__with_lock(ocb->dst_wcroot->sdb,
5224
 
                                              op_copy_shadowed_layer_txn,
5225
 
                                              ocb, scratch_pool));
 
5547
      /* Source and destination databases differ; so also start a lock
 
5548
         in the destination database, by calling ourself in an extra lock. */
 
5549
 
 
5550
      SVN_WC__DB_WITH_TXN(op_copy_shadowed_layer_txn(ocb->dst_wcroot, ocb,
 
5551
                                                     scratch_pool),
 
5552
                          ocb->dst_wcroot);
 
5553
 
 
5554
      return SVN_NO_ERROR;
5226
5555
    }
5227
5556
 
5228
5557
  /* From this point we can assume a lock in the src and dst databases */
5304
5633
 
5305
5634
  /* Call with the sdb in src_wcroot. It might call itself again to
5306
5635
     also obtain a lock in dst_wcroot */
5307
 
  SVN_ERR(svn_sqlite__with_lock(ocb.src_wcroot->sdb,
5308
 
                                op_copy_shadowed_layer_txn,
5309
 
                                &ocb, scratch_pool));
 
5636
  SVN_WC__DB_WITH_TXN(op_copy_shadowed_layer_txn(ocb.src_wcroot, &ocb,
 
5637
                                                 scratch_pool),
 
5638
                      ocb.src_wcroot);
5310
5639
 
5311
5640
  return SVN_NO_ERROR;
5312
5641
}
5776
6105
 * props; to indicate no properties when the pristine has some props,
5777
6106
 * PROPS must be an empty hash. */
5778
6107
static svn_error_t *
5779
 
set_actual_props(apr_int64_t wc_id,
 
6108
set_actual_props(svn_wc__db_wcroot_t *wcroot,
5780
6109
                 const char *local_relpath,
5781
6110
                 apr_hash_t *props,
5782
 
                 svn_sqlite__db_t *db,
5783
6111
                 apr_pool_t *scratch_pool)
5784
6112
{
5785
6113
  svn_sqlite__stmt_t *stmt;
5786
6114
  int affected_rows;
5787
6115
 
5788
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_UPDATE_ACTUAL_PROPS));
5789
 
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
 
6116
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
6117
                                    STMT_UPDATE_ACTUAL_PROPS));
 
6118
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
5790
6119
  SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
5791
6120
  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
5792
6121
 
5793
6122
  if (affected_rows == 1 || !props)
5794
 
    return SVN_NO_ERROR; /* We are done */
 
6123
    {
 
6124
      /* Perhaps the entire ACTUAL record is unneeded now? */
 
6125
      if (!props && affected_rows)
 
6126
        {
 
6127
          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
6128
                                            STMT_DELETE_ACTUAL_EMPTY));
 
6129
          SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
6130
          SVN_ERR(svn_sqlite__step_done(stmt));
 
6131
        }
 
6132
 
 
6133
      return SVN_NO_ERROR; /* We are done */
 
6134
    }
5795
6135
 
5796
6136
  /* We have to insert a row in ACTUAL */
5797
6137
 
5798
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_ACTUAL_PROPS));
5799
 
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
 
6138
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
6139
                                    STMT_INSERT_ACTUAL_PROPS));
 
6140
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
5800
6141
  if (*local_relpath != '\0')
5801
6142
    SVN_ERR(svn_sqlite__bind_text(stmt, 3,
5802
6143
                                  svn_relpath_dirname(local_relpath,
5805
6146
  return svn_error_trace(svn_sqlite__step_done(stmt));
5806
6147
}
5807
6148
 
 
6149
svn_error_t *
 
6150
svn_wc__db_op_set_props_internal(svn_wc__db_wcroot_t *wcroot,
 
6151
                                 const char *local_relpath,
 
6152
                                 apr_hash_t *props,
 
6153
                                 svn_boolean_t clear_recorded_info,
 
6154
                                 apr_pool_t *scratch_pool)
 
6155
{
 
6156
  SVN_ERR(set_actual_props(wcroot, local_relpath, props, scratch_pool));
 
6157
 
 
6158
  if (clear_recorded_info)
 
6159
    {
 
6160
      SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
 
6161
                                 SVN_INVALID_FILESIZE, 0,
 
6162
                                 scratch_pool));
 
6163
    }
 
6164
 
 
6165
  return SVN_NO_ERROR;
 
6166
}
5808
6167
 
5809
6168
/* The body of svn_wc__db_op_set_props().
5810
6169
 
5840
6199
        props = NULL;
5841
6200
    }
5842
6201
 
5843
 
  SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath,
5844
 
                           props, wcroot->sdb, scratch_pool));
5845
 
 
5846
 
  if (clear_recorded_info)
5847
 
    {
5848
 
      SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
5849
 
                                 SVN_INVALID_FILESIZE, 0,
5850
 
                                 scratch_pool));
5851
 
    }
 
6202
  SVN_ERR(svn_wc__db_op_set_props_internal(wcroot, local_relpath, props,
 
6203
                                           clear_recorded_info, scratch_pool));
5852
6204
 
5853
6205
  /* And finally.  */
5854
6206
  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
6080
6432
  if (scb->new_changelist)
6081
6433
    {
6082
6434
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
6083
 
                                        STMT_INSERT_ACTUAL_EMPTIES));
 
6435
                                        STMT_INSERT_ACTUAL_EMPTIES_FILES));
6084
6436
      SVN_ERR(svn_sqlite__step_done(stmt));
6085
6437
    }
6086
6438
 
6297
6649
 
6298
6650
/* The body of svn_wc__db_op_mark_resolved().
6299
6651
 */
6300
 
static svn_error_t *
6301
 
db_op_mark_resolved(svn_wc__db_wcroot_t *wcroot,
6302
 
                    const char *local_relpath,
6303
 
                    svn_wc__db_t *db,
6304
 
                    svn_boolean_t resolved_text,
6305
 
                    svn_boolean_t resolved_props,
6306
 
                    svn_boolean_t resolved_tree,
6307
 
                    const svn_skel_t *work_items,
6308
 
                    apr_pool_t *scratch_pool)
 
6652
svn_error_t *
 
6653
svn_wc__db_op_mark_resolved_internal(svn_wc__db_wcroot_t *wcroot,
 
6654
                                     const char *local_relpath,
 
6655
                                     svn_wc__db_t *db,
 
6656
                                     svn_boolean_t resolved_text,
 
6657
                                     svn_boolean_t resolved_props,
 
6658
                                     svn_boolean_t resolved_tree,
 
6659
                                     const svn_skel_t *work_items,
 
6660
                                     apr_pool_t *scratch_pool)
6309
6661
{
6310
6662
  svn_sqlite__stmt_t *stmt;
6311
6663
  svn_boolean_t have_row;
6403
6755
  VERIFY_USABLE_WCROOT(wcroot);
6404
6756
 
6405
6757
  SVN_WC__DB_WITH_TXN(
6406
 
    db_op_mark_resolved(wcroot, local_relpath, db,
 
6758
    svn_wc__db_op_mark_resolved_internal(
 
6759
                        wcroot, local_relpath, db,
6407
6760
                        resolved_text, resolved_props, resolved_tree,
6408
6761
                        work_items, scratch_pool),
6409
6762
    wcroot);
6412
6765
  return SVN_NO_ERROR;
6413
6766
}
6414
6767
 
6415
 
/* Clear moved-to information at the delete-half of the move which
6416
 
 * moved LOCAL_RELPATH here. This transforms the move into a simple delete. */
 
6768
/* Clear moved-to information at the delete-half of the move which moved
 
6769
 * MOVED_TO_RELPATH here. This transforms the delete part of the move into a
 
6770
 * normal delete.
 
6771
 *
 
6772
 * Note that the moved-to location is always an op-root, while this is not the
 
6773
 * case for a moved-from location.
 
6774
 */
6417
6775
static svn_error_t *
6418
 
clear_moved_to(const char *local_relpath,
6419
 
               svn_wc__db_wcroot_t *wcroot,
 
6776
clear_moved_to(svn_wc__db_wcroot_t *wcroot,
 
6777
               const char *moved_to_relpath,
6420
6778
               apr_pool_t *scratch_pool)
6421
6779
{
6422
6780
  svn_sqlite__stmt_t *stmt;
6423
 
  svn_boolean_t have_row;
6424
6781
  const char *moved_from_relpath;
 
6782
  int moved_from_op_depth;
6425
6783
 
6426
6784
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
6427
6785
                                    STMT_SELECT_MOVED_FROM_RELPATH));
6428
 
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
6429
 
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
6430
 
  if (!have_row)
6431
 
    {
6432
 
      SVN_ERR(svn_sqlite__reset(stmt));
6433
 
      return SVN_NO_ERROR;
6434
 
    }
 
6786
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, moved_to_relpath));
 
6787
  SVN_ERR(svn_sqlite__step_row(stmt));
6435
6788
 
6436
6789
  moved_from_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
 
6790
  moved_from_op_depth = svn_sqlite__column_int(stmt, 1);
6437
6791
  SVN_ERR(svn_sqlite__reset(stmt));
6438
6792
 
6439
6793
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
6440
6794
                                    STMT_CLEAR_MOVED_TO_RELPATH));
6441
6795
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
6442
 
                            moved_from_relpath,
6443
 
                            relpath_depth(moved_from_relpath)));
6444
 
  SVN_ERR(svn_sqlite__step_done(stmt));
 
6796
                            moved_from_relpath, moved_from_op_depth));
 
6797
  SVN_ERR(svn_sqlite__update(NULL, stmt));
6445
6798
 
6446
6799
  return SVN_NO_ERROR;
6447
6800
}
6448
6801
 
 
6802
/* Baton for op_revert_txn and op_revert_recursive_txn */
 
6803
struct revert_baton_t
 
6804
{
 
6805
  svn_wc__db_t *db;
 
6806
  svn_boolean_t clear_changelists;
 
6807
};
 
6808
 
6449
6809
/* One of the two alternative bodies of svn_wc__db_op_revert().
6450
6810
 *
6451
6811
 * Implements svn_wc__db_txn_callback_t. */
6455
6815
              const char *local_relpath,
6456
6816
              apr_pool_t *scratch_pool)
6457
6817
{
6458
 
  svn_wc__db_t *db = baton;
 
6818
  struct revert_baton_t *rvb = baton;
 
6819
  svn_wc__db_t *db = rvb->db;
6459
6820
  svn_sqlite__stmt_t *stmt;
6460
6821
  svn_boolean_t have_row;
6461
6822
  int op_depth;
6462
6823
  svn_boolean_t moved_here;
6463
6824
  int affected_rows;
6464
6825
  const char *moved_to;
 
6826
  int op_depth_increased = 0;
 
6827
  int op_depth_below;
 
6828
  svn_skel_t *conflict;
6465
6829
 
6466
6830
  /* ### Similar structure to op_revert_recursive_txn, should they be
6467
6831
         combined? */
6508
6872
  op_depth = svn_sqlite__column_int(stmt, 0);
6509
6873
  moved_here = svn_sqlite__column_boolean(stmt, 15);
6510
6874
  moved_to = svn_sqlite__column_text(stmt, 17, scratch_pool);
 
6875
 
 
6876
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
6877
  if (have_row)
 
6878
    op_depth_below = svn_sqlite__column_int(stmt, 0);
 
6879
  else
 
6880
    op_depth_below = -1;
 
6881
 
6511
6882
  SVN_ERR(svn_sqlite__reset(stmt));
6512
6883
 
6513
6884
  if (moved_to)
6514
6885
    {
6515
 
      SVN_ERR(svn_wc__db_resolve_break_moved_away_internal(wcroot,
6516
 
                                                           local_relpath,
6517
 
                                                           op_depth,
6518
 
                                                           scratch_pool));
 
6886
      SVN_ERR(svn_wc__db_op_break_move_internal(wcroot,
 
6887
                                                local_relpath, op_depth,
 
6888
                                                moved_to, NULL, scratch_pool));
6519
6889
    }
6520
6890
  else
6521
6891
    {
6522
 
      svn_skel_t *conflict;
6523
 
 
6524
 
      SVN_ERR(svn_wc__db_read_conflict_internal(&conflict, wcroot,
 
6892
      SVN_ERR(svn_wc__db_read_conflict_internal(&conflict, NULL, NULL, wcroot,
6525
6893
                                                local_relpath,
6526
6894
                                                scratch_pool, scratch_pool));
6527
 
      if (conflict)
6528
 
        {
6529
 
          svn_wc_operation_t operation;
6530
 
          svn_boolean_t tree_conflicted;
6531
 
 
6532
 
          SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL,
6533
 
                                             &tree_conflicted,
6534
 
                                             db, wcroot->abspath,
6535
 
                                             conflict,
6536
 
                                             scratch_pool, scratch_pool));
6537
 
          if (tree_conflicted
6538
 
              && (operation == svn_wc_operation_update
6539
 
                  || operation == svn_wc_operation_switch))
6540
 
            {
6541
 
              svn_wc_conflict_reason_t reason;
6542
 
              svn_wc_conflict_action_t action;
6543
 
 
6544
 
              SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action,
6545
 
                                                          NULL,
6546
 
                                                          db, wcroot->abspath,
6547
 
                                                          conflict,
6548
 
                                                          scratch_pool,
6549
 
                                                          scratch_pool));
6550
 
 
6551
 
              if (reason == svn_wc_conflict_reason_deleted)
6552
 
                SVN_ERR(svn_wc__db_resolve_delete_raise_moved_away(
6553
 
                          db, svn_dirent_join(wcroot->abspath, local_relpath,
6554
 
                                              scratch_pool),
6555
 
                          NULL, NULL /* ### How do we notify this? */,
6556
 
                          scratch_pool));
6557
 
            }
6558
 
        }
6559
6895
    }
6560
6896
 
 
6897
 
6561
6898
  if (op_depth > 0 && op_depth == relpath_depth(local_relpath))
6562
6899
    {
6563
6900
      /* Can't do non-recursive revert if children exist */
6582
6919
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
6583
6920
                                local_relpath,
6584
6921
                                op_depth));
6585
 
      SVN_ERR(svn_sqlite__step_done(stmt));
 
6922
      SVN_ERR(svn_sqlite__update(&op_depth_increased, stmt));
6586
6923
 
6587
6924
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
6588
6925
                                        STMT_DELETE_WORKING_NODE));
6597
6934
 
6598
6935
      /* If this node was moved-here, clear moved-to at the move source. */
6599
6936
      if (moved_here)
6600
 
        SVN_ERR(clear_moved_to(local_relpath, wcroot, scratch_pool));
6601
 
    }
6602
 
 
6603
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
6937
        SVN_ERR(clear_moved_to(wcroot, local_relpath, scratch_pool));
 
6938
    }
 
6939
 
 
6940
  if (op_depth_increased && conflict)
 
6941
    {
 
6942
      svn_wc_operation_t operation;
 
6943
      svn_boolean_t tree_conflicted;
 
6944
      const apr_array_header_t *locations;
 
6945
 
 
6946
      SVN_ERR(svn_wc__conflict_read_info(&operation, &locations, NULL, NULL,
 
6947
                                          &tree_conflicted,
 
6948
                                          db, wcroot->abspath,
 
6949
                                          conflict,
 
6950
                                          scratch_pool, scratch_pool));
 
6951
      if (tree_conflicted
 
6952
          && (operation == svn_wc_operation_update
 
6953
              || operation == svn_wc_operation_switch))
 
6954
        {
 
6955
          svn_wc_conflict_reason_t reason;
 
6956
          svn_wc_conflict_action_t action;
 
6957
 
 
6958
          SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action,
 
6959
                                                      NULL,
 
6960
                                                      db, wcroot->abspath,
 
6961
                                                      conflict,
 
6962
                                                      scratch_pool,
 
6963
                                                      scratch_pool));
 
6964
 
 
6965
          if (reason == svn_wc_conflict_reason_deleted
 
6966
              || reason == svn_wc_conflict_reason_replaced)
 
6967
            {
 
6968
              SVN_ERR(svn_wc__db_op_raise_moved_away_internal(
 
6969
                          wcroot, local_relpath, op_depth_below, db,
 
6970
                          operation, action,
 
6971
                          (locations && locations->nelts > 0)
 
6972
                            ? APR_ARRAY_IDX(locations, 0,
 
6973
                                            const svn_wc_conflict_version_t *)
 
6974
                            : NULL,
 
6975
                          (locations && locations->nelts > 1)
 
6976
                            ? APR_ARRAY_IDX(locations, 1,
 
6977
                                            const svn_wc_conflict_version_t *)
 
6978
                            : NULL,
 
6979
                          scratch_pool));
 
6980
 
 
6981
              /* Transform the move information into revert information */
 
6982
              SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
 
6983
                                                  STMT_MOVE_NOTIFY_TO_REVERT));
 
6984
            }
 
6985
        }
 
6986
    }
 
6987
 
 
6988
  if (rvb->clear_changelists)
 
6989
    {
 
6990
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
6991
                                        STMT_DELETE_ACTUAL_NODE));
 
6992
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
6993
      SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
6994
    }
 
6995
  else
 
6996
    {
 
6997
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
6604
6998
                                  STMT_DELETE_ACTUAL_NODE_LEAVING_CHANGELIST));
6605
 
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
6606
 
  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
6607
 
  if (!affected_rows)
6608
 
    {
6609
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
6610
 
                                    STMT_CLEAR_ACTUAL_NODE_LEAVING_CHANGELIST));
6611
6999
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
6612
7000
      SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
7001
      if (!affected_rows)
 
7002
        {
 
7003
          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
7004
                                  STMT_CLEAR_ACTUAL_NODE_LEAVING_CHANGELIST));
 
7005
          SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
7006
          SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
7007
        }
6613
7008
    }
6614
7009
 
6615
7010
  return SVN_NO_ERROR;
6625
7020
                        const char *local_relpath,
6626
7021
                        apr_pool_t *scratch_pool)
6627
7022
{
 
7023
  struct revert_baton_t *rvb = baton;
6628
7024
  svn_sqlite__stmt_t *stmt;
6629
7025
  svn_boolean_t have_row;
6630
7026
  int op_depth;
6680
7076
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
6681
7077
  while (have_row)
6682
7078
    {
6683
 
      const char *move_src_relpath = svn_sqlite__column_text(stmt, 0, NULL);
 
7079
      const char *src_relpath = svn_sqlite__column_text(stmt, 0, NULL);
 
7080
      const char *dst_relpath = svn_sqlite__column_text(stmt, 1, NULL);
6684
7081
      int move_op_depth = svn_sqlite__column_int(stmt, 2);
6685
7082
      svn_error_t *err;
6686
7083
 
6687
 
      err = svn_wc__db_resolve_break_moved_away_internal(wcroot,
6688
 
                                                         move_src_relpath,
6689
 
                                                         move_op_depth,
6690
 
                                                         scratch_pool);
 
7084
      err = svn_wc__db_op_break_move_internal(wcroot,
 
7085
                                              src_relpath, move_op_depth,
 
7086
                                              dst_relpath, NULL, scratch_pool);
6691
7087
      if (err)
6692
7088
        return svn_error_compose_create(err, svn_sqlite__reset(stmt));
6693
7089
 
6706
7102
                            local_relpath, select_op_depth));
6707
7103
  SVN_ERR(svn_sqlite__step_done(stmt));
6708
7104
 
6709
 
  SVN_ERR(svn_sqlite__get_statement(
6710
 
                    &stmt, wcroot->sdb,
6711
 
                    STMT_DELETE_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE));
6712
 
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
6713
 
  SVN_ERR(svn_sqlite__step_done(stmt));
 
7105
  if (rvb->clear_changelists)
 
7106
    {
 
7107
      SVN_ERR(svn_sqlite__get_statement(
 
7108
                        &stmt, wcroot->sdb,
 
7109
                        STMT_DELETE_ACTUAL_NODE_RECURSIVE));
 
7110
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
7111
      SVN_ERR(svn_sqlite__step_done(stmt));
 
7112
    }
 
7113
  else
 
7114
    {
 
7115
      SVN_ERR(svn_sqlite__get_statement(
 
7116
                        &stmt, wcroot->sdb,
 
7117
                        STMT_DELETE_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE));
 
7118
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
7119
      SVN_ERR(svn_sqlite__step_done(stmt));
6714
7120
 
6715
 
  SVN_ERR(svn_sqlite__get_statement(
6716
 
                    &stmt, wcroot->sdb,
6717
 
                    STMT_CLEAR_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE));
6718
 
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
6719
 
  SVN_ERR(svn_sqlite__step_done(stmt));
 
7121
      SVN_ERR(svn_sqlite__get_statement(
 
7122
                        &stmt, wcroot->sdb,
 
7123
                        STMT_CLEAR_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE));
 
7124
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
7125
      SVN_ERR(svn_sqlite__step_done(stmt));
 
7126
    }
6720
7127
 
6721
7128
  /* ### This removes the locks, but what about the access batons? */
6722
7129
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
6740
7147
      svn_pool_clear(iterpool);
6741
7148
 
6742
7149
      moved_here_child_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
6743
 
      err = clear_moved_to(moved_here_child_relpath, wcroot, iterpool);
 
7150
      err = clear_moved_to(wcroot, moved_here_child_relpath, iterpool);
6744
7151
      if (err)
6745
7152
        return svn_error_trace(svn_error_compose_create(
6746
7153
                                        err,
6754
7161
  /* Clear potential moved-to pointing at the target node itself. */
6755
7162
  if (op_depth > 0 && op_depth == relpath_depth(local_relpath)
6756
7163
      && moved_here)
6757
 
    SVN_ERR(clear_moved_to(local_relpath, wcroot, scratch_pool));
 
7164
    SVN_ERR(clear_moved_to(wcroot, local_relpath, scratch_pool));
6758
7165
 
6759
7166
  return SVN_NO_ERROR;
6760
7167
}
6763
7170
svn_wc__db_op_revert(svn_wc__db_t *db,
6764
7171
                     const char *local_abspath,
6765
7172
                     svn_depth_t depth,
 
7173
                     svn_boolean_t clear_changelists,
6766
7174
                     apr_pool_t *result_pool,
6767
7175
                     apr_pool_t *scratch_pool)
6768
7176
{
6769
7177
  svn_wc__db_wcroot_t *wcroot;
6770
7178
  const char *local_relpath;
 
7179
  struct revert_baton_t rvb;
6771
7180
  struct with_triggers_baton_t wtb = { STMT_CREATE_REVERT_LIST,
6772
7181
                                       STMT_DROP_REVERT_LIST_TRIGGERS,
6773
7182
                                       NULL, NULL};
6774
7183
 
6775
7184
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
6776
7185
 
 
7186
  rvb.db = db;
 
7187
  rvb.clear_changelists = clear_changelists;
 
7188
  wtb.cb_baton = &rvb;
 
7189
 
6777
7190
  switch (depth)
6778
7191
    {
6779
7192
    case svn_depth_empty:
6780
7193
      wtb.cb_func = op_revert_txn;
6781
 
      wtb.cb_baton = db;
6782
7194
      break;
6783
7195
    case svn_depth_infinity:
6784
7196
      wtb.cb_func = op_revert_recursive_txn;
6914
7326
static svn_error_t *
6915
7327
revert_list_read_copied_children(svn_wc__db_wcroot_t *wcroot,
6916
7328
                                 const char *local_relpath,
6917
 
                                 const apr_array_header_t **children_p,
 
7329
                                 apr_array_header_t **children_p,
6918
7330
                                 apr_pool_t *result_pool,
6919
7331
                                 apr_pool_t *scratch_pool)
6920
7332
{
6957
7369
 
6958
7370
 
6959
7371
svn_error_t *
6960
 
svn_wc__db_revert_list_read_copied_children(const apr_array_header_t **children,
 
7372
svn_wc__db_revert_list_read_copied_children(apr_array_header_t **children,
6961
7373
                                            svn_wc__db_t *db,
6962
7374
                                            const char *local_abspath,
6963
7375
                                            apr_pool_t *result_pool,
7004
7416
  while (have_row)
7005
7417
    {
7006
7418
      const char *notify_relpath = svn_sqlite__column_text(stmt, 0, NULL);
 
7419
      svn_wc_notify_t *notify;
7007
7420
 
7008
7421
      svn_pool_clear(iterpool);
7009
7422
 
7010
 
      notify_func(notify_baton,
7011
 
                  svn_wc_create_notify(svn_dirent_join(wcroot->abspath,
7012
 
                                                       notify_relpath,
7013
 
                                                       iterpool),
7014
 
                                       svn_wc_notify_revert,
7015
 
                                       iterpool),
7016
 
                  iterpool);
 
7423
      notify = svn_wc_create_notify(svn_dirent_join(wcroot->abspath,
 
7424
                                                    notify_relpath,
 
7425
                                                    iterpool),
 
7426
                                    svn_wc_notify_revert,
 
7427
                                    iterpool);
 
7428
 
 
7429
      if (!svn_sqlite__column_is_null(stmt, 1))
 
7430
        notify->kind = svn_sqlite__column_token(stmt, 1, kind_map);
 
7431
      else
 
7432
        {
 
7433
          if (!svn_sqlite__column_is_null(stmt, 3))
 
7434
            notify->kind = svn_sqlite__column_token(stmt, 3, kind_map_none);
 
7435
 
 
7436
          switch (svn_sqlite__column_int(stmt, 2))
 
7437
            {
 
7438
              case 0:
 
7439
                continue;
 
7440
              case 1:
 
7441
                /* standard revert */
 
7442
                break;
 
7443
              case 2:
 
7444
                notify->action = svn_wc_notify_tree_conflict;
 
7445
                break;
 
7446
              default:
 
7447
                SVN_ERR_MALFUNCTION();
 
7448
            }
 
7449
        }
 
7450
 
 
7451
      notify_func(notify_baton, notify, iterpool);
7017
7452
 
7018
7453
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
7019
7454
    }
7055
7490
                svn_wc__db_t *db,
7056
7491
                svn_boolean_t destroy_wc,
7057
7492
                svn_boolean_t destroy_changes,
7058
 
                svn_revnum_t not_present_rev,
7059
 
                svn_wc__db_status_t not_present_status,
7060
 
                svn_node_kind_t not_present_kind,
7061
7493
                const svn_skel_t *conflict,
7062
7494
                const svn_skel_t *work_items,
7063
7495
                svn_cancel_func_t cancel_func,
7066
7498
{
7067
7499
  svn_sqlite__stmt_t *stmt;
7068
7500
 
7069
 
  apr_int64_t repos_id;
7070
 
  const char *repos_relpath;
7071
 
 
7072
7501
  /* Note that unlike many similar functions it is a valid scenario for this
7073
7502
     function to be called on a wcroot! */
7074
7503
 
7078
7507
  if (left_changes)
7079
7508
    *left_changes = FALSE;
7080
7509
 
7081
 
  /* Need info for not_present node? */
7082
 
  if (SVN_IS_VALID_REVNUM(not_present_rev))
7083
 
    SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
7084
 
                                              &repos_relpath, &repos_id,
7085
 
                                              NULL, NULL, NULL, NULL, NULL,
7086
 
                                              NULL, NULL, NULL, NULL, NULL,
7087
 
                                              wcroot, local_relpath,
7088
 
                                              scratch_pool, scratch_pool));
7089
 
 
7090
7510
  if (destroy_wc
7091
7511
      && (!destroy_changes || *local_relpath == '\0'))
7092
7512
    {
7283
7703
                                         local_relpath));
7284
7704
  SVN_ERR(svn_sqlite__step_done(stmt));
7285
7705
 
7286
 
  /* Should we leave a not-present node? */
7287
 
  if (SVN_IS_VALID_REVNUM(not_present_rev))
7288
 
    {
7289
 
      insert_base_baton_t ibb;
7290
 
      blank_ibb(&ibb);
7291
 
 
7292
 
      ibb.repos_id = repos_id;
7293
 
 
7294
 
      SVN_ERR_ASSERT(not_present_status == svn_wc__db_status_not_present
7295
 
                     || not_present_status == svn_wc__db_status_excluded);
7296
 
 
7297
 
      ibb.status = not_present_status;
7298
 
      ibb.kind = not_present_kind;
7299
 
 
7300
 
      ibb.repos_relpath = repos_relpath;
7301
 
      ibb.revision = not_present_rev;
7302
 
 
7303
 
      SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
7304
 
    }
7305
 
 
7306
7706
  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
7307
7707
  if (conflict)
7308
7708
    SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
7317
7717
                          const char *local_abspath,
7318
7718
                          svn_boolean_t destroy_wc,
7319
7719
                          svn_boolean_t destroy_changes,
7320
 
                          svn_revnum_t not_present_revision,
7321
 
                          svn_wc__db_status_t not_present_status,
7322
 
                          svn_node_kind_t not_present_kind,
7323
7720
                          const svn_skel_t *conflict,
7324
7721
                          const svn_skel_t *work_items,
7325
7722
                          svn_cancel_func_t cancel_func,
7338
7735
  SVN_WC__DB_WITH_TXN(remove_node_txn(left_changes,
7339
7736
                                      wcroot, local_relpath, db,
7340
7737
                                      destroy_wc, destroy_changes,
7341
 
                                      not_present_revision, not_present_status,
7342
 
                                      not_present_kind, conflict, work_items,
 
7738
                                      conflict, work_items,
7343
7739
                                      cancel_func, cancel_baton, scratch_pool),
7344
7740
                      wcroot);
7345
7741
 
7371
7767
 
7372
7768
  if (affected_rows == 0)
7373
7769
    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
7374
 
                             "The node '%s' is not a committed directory",
 
7770
                             _("The node '%s' is not a committed directory"),
7375
7771
                             path_for_error_message(wcroot, local_relpath,
7376
7772
                                                    scratch_pool));
7377
7773
 
8109
8505
  apr_array_header_t *rel_targets;
8110
8506
  svn_boolean_t delete_dir_externals;
8111
8507
  const svn_skel_t *work_items;
8112
 
} op_delete_many_baton_t;
 
8508
};
8113
8509
 
8114
8510
static svn_error_t *
8115
8511
op_delete_many_txn(void *baton,
8666
9062
    err = svn_error_compose_create(err, svn_sqlite__reset(stmt_act));
8667
9063
 
8668
9064
  if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
8669
 
    err = svn_error_quick_wrap(err,
8670
 
                               apr_psprintf(scratch_pool,
8671
 
                                            "Error reading node '%s'",
8672
 
                                            local_relpath));
 
9065
    err = svn_error_quick_wrapf(err, _("Error reading node '%s'"),
 
9066
                                local_relpath);
8673
9067
 
8674
9068
  SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt_info)));
8675
9069
 
8773
9167
                    have_base, have_more_work, have_work,
8774
9168
                    wcroot, local_relpath, result_pool, scratch_pool),
8775
9169
          svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
8776
 
                                      wcroot->sdb, repos_id, result_pool),
 
9170
                                      wcroot, repos_id, result_pool),
8777
9171
          svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
8778
 
                                      wcroot->sdb, original_repos_id,
 
9172
                                      wcroot, original_repos_id,
8779
9173
                                      result_pool),
8780
9174
        SVN_NO_ERROR,
8781
9175
        wcroot);
8789
9183
            const char *dir_relpath,
8790
9184
            apr_pool_t *scratch_pool);
8791
9185
 
 
9186
/* Helper for read_children_info and single variant */
 
9187
static svn_error_t *
 
9188
find_conflict_descendants(svn_boolean_t *conflict_exists,
 
9189
                          svn_wc__db_wcroot_t *wcroot,
 
9190
                          const char *local_relpath,
 
9191
                          apr_pool_t *scratch_pool)
 
9192
{
 
9193
  svn_sqlite__stmt_t *stmt;
 
9194
 
 
9195
  /* Only used on files, so certainly not wcroot*/
 
9196
  assert(local_relpath[0] != '\0');
 
9197
 
 
9198
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
9199
                                    STMT_FIND_CONFLICT_DESCENDANT));
 
9200
 
 
9201
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
9202
  SVN_ERR(svn_sqlite__step(conflict_exists, stmt));
 
9203
 
 
9204
  return svn_error_trace(svn_sqlite__reset(stmt));
 
9205
}
 
9206
 
8792
9207
/* What we really want to store about a node.  This relies on the
8793
9208
   offset of svn_wc__db_info_t being zero. */
8794
9209
struct read_children_info_item_t
8796
9211
  struct svn_wc__db_info_t info;
8797
9212
  int op_depth;
8798
9213
  int nr_layers;
 
9214
  svn_boolean_t was_dir;
8799
9215
};
8800
9216
 
 
9217
/* Implementation of svn_wc__db_read_children_info */
8801
9218
static svn_error_t *
8802
9219
read_children_info(svn_wc__db_wcroot_t *wcroot,
8803
9220
                   const char *dir_relpath,
8804
9221
                   apr_hash_t *conflicts,
8805
9222
                   apr_hash_t *nodes,
 
9223
                   svn_boolean_t base_tree_only,
8806
9224
                   apr_pool_t *result_pool,
8807
9225
                   apr_pool_t *scratch_pool)
8808
9226
{
8811
9229
  const char *repos_root_url = NULL;
8812
9230
  const char *repos_uuid = NULL;
8813
9231
  apr_int64_t last_repos_id = INVALID_REPOS_ID;
 
9232
  const char *last_repos_root_url = NULL;
8814
9233
 
8815
9234
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
8816
 
                                    STMT_SELECT_NODE_CHILDREN_INFO));
 
9235
                                    (base_tree_only
 
9236
                                     ? STMT_SELECT_BASE_NODE_CHILDREN_INFO
 
9237
                                     : STMT_SELECT_NODE_CHILDREN_INFO)));
8817
9238
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, dir_relpath));
8818
9239
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
8819
9240
 
8828
9249
      int op_depth;
8829
9250
      svn_boolean_t new_child;
8830
9251
 
8831
 
      child_item = svn_hash_gets(nodes, name);
 
9252
      child_item = (base_tree_only ? NULL : svn_hash_gets(nodes, name));
8832
9253
      if (child_item)
8833
9254
        new_child = FALSE;
8834
9255
      else
8840
9261
      op_depth = svn_sqlite__column_int(stmt, 0);
8841
9262
 
8842
9263
      /* Do we have new or better information? */
8843
 
      if (new_child || op_depth > child_item->op_depth)
 
9264
      if (new_child)
8844
9265
        {
8845
9266
          struct svn_wc__db_info_t *child = &child_item->info;
8846
9267
          child_item->op_depth = op_depth;
8875
9296
            }
8876
9297
          else
8877
9298
            {
8878
 
              const char *last_repos_root_url = NULL;
8879
 
 
8880
9299
              apr_int64_t repos_id = svn_sqlite__column_int64(stmt, 1);
8881
9300
              if (!repos_root_url ||
8882
9301
                  (last_repos_id != INVALID_REPOS_ID &&
8885
9304
                  last_repos_root_url = repos_root_url;
8886
9305
                  err = svn_wc__db_fetch_repos_info(&repos_root_url,
8887
9306
                                                    &repos_uuid,
8888
 
                                                    wcroot->sdb, repos_id,
 
9307
                                                    wcroot, repos_id,
8889
9308
                                                    result_pool);
8890
9309
                  if (err)
8891
9310
                    SVN_ERR(svn_error_compose_create(err,
8923
9342
            child->depth = svn_depth_unknown;
8924
9343
          else
8925
9344
            {
 
9345
              child->has_descendants = TRUE;
 
9346
              child_item->was_dir = TRUE;
8926
9347
              child->depth = svn_sqlite__column_token_null(stmt, 11, depth_map,
8927
9348
                                                           svn_depth_unknown);
8928
9349
              if (new_child)
8929
 
                SVN_ERR(is_wclocked(&child->locked, wcroot, child_relpath,
8930
 
                                    scratch_pool));
 
9350
                {
 
9351
                  err = is_wclocked(&child->locked, wcroot, child_relpath,
 
9352
                                    scratch_pool);
 
9353
 
 
9354
                  if (err)
 
9355
                    SVN_ERR(svn_error_compose_create(err,
 
9356
                                                     svn_sqlite__reset(stmt)));
 
9357
                }
8931
9358
            }
8932
9359
 
8933
9360
          child->recorded_time = svn_sqlite__column_int64(stmt, 13);
8959
9386
          if (new_child)
8960
9387
            svn_hash_sets(nodes, apr_pstrdup(result_pool, name), child);
8961
9388
        }
 
9389
      else if (!child_item->was_dir
 
9390
               && svn_sqlite__column_token(stmt, 4, kind_map) == svn_node_dir)
 
9391
        {
 
9392
          child_item->was_dir = TRUE;
 
9393
 
 
9394
          err = find_conflict_descendants(&child_item->info.has_descendants,
 
9395
                                          wcroot, child_relpath,
 
9396
                                          scratch_pool);
 
9397
          if (err)
 
9398
            SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
 
9399
        }
8962
9400
 
8963
9401
      if (op_depth == 0)
8964
9402
        {
8990
9428
              struct svn_wc__db_moved_to_info_t *moved_to;
8991
9429
              struct svn_wc__db_moved_to_info_t **next;
8992
9430
              const char *shadow_op_relpath;
8993
 
              int cur_op_depth;
8994
9431
 
8995
9432
              moved_to = apr_pcalloc(result_pool, sizeof(*moved_to));
8996
9433
              moved_to->moved_to_abspath = svn_dirent_join(wcroot->abspath,
8997
9434
                                                           moved_to_relpath,
8998
9435
                                                           result_pool);
8999
9436
 
9000
 
              cur_op_depth = relpath_depth(child_relpath);
9001
 
              shadow_op_relpath = child_relpath;
9002
 
 
9003
 
              while (cur_op_depth > op_depth)
9004
 
                {
9005
 
                  shadow_op_relpath = svn_relpath_dirname(shadow_op_relpath,
9006
 
                                                          scratch_pool);
9007
 
                  cur_op_depth--;
9008
 
                }
 
9437
              shadow_op_relpath = svn_relpath_prefix(child_relpath, op_depth,
 
9438
                                                     scratch_pool);
9009
9439
 
9010
9440
              moved_to->shadow_op_root_abspath =
9011
9441
                        svn_dirent_join(wcroot->abspath, shadow_op_relpath,
9028
9458
 
9029
9459
  SVN_ERR(svn_sqlite__reset(stmt));
9030
9460
 
9031
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
9032
 
                                    STMT_SELECT_ACTUAL_CHILDREN_INFO));
9033
 
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, dir_relpath));
9034
 
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
9035
 
 
9036
 
  while (have_row)
 
9461
  if (!base_tree_only)
9037
9462
    {
9038
 
      struct read_children_info_item_t *child_item;
9039
 
      struct svn_wc__db_info_t *child;
9040
 
      const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
9041
 
      const char *name = svn_relpath_basename(child_relpath, NULL);
 
9463
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
9464
                                        STMT_SELECT_ACTUAL_CHILDREN_INFO));
 
9465
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, dir_relpath));
 
9466
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
9042
9467
 
9043
 
      child_item = svn_hash_gets(nodes, name);
9044
 
      if (!child_item)
 
9468
      while (have_row)
9045
9469
        {
9046
 
          child_item = apr_pcalloc(result_pool, sizeof(*child_item));
9047
 
          child_item->info.status = svn_wc__db_status_not_present;
9048
 
        }
9049
 
 
9050
 
      child = &child_item->info;
9051
 
 
9052
 
      child->changelist = svn_sqlite__column_text(stmt, 1, result_pool);
9053
 
 
9054
 
      child->props_mod = !svn_sqlite__column_is_null(stmt, 2);
 
9470
          struct read_children_info_item_t *child_item;
 
9471
          struct svn_wc__db_info_t *child;
 
9472
          const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
 
9473
          const char *name = svn_relpath_basename(child_relpath, NULL);
 
9474
 
 
9475
          child_item = svn_hash_gets(nodes, name);
 
9476
          if (!child_item)
 
9477
            {
 
9478
              child_item = apr_pcalloc(result_pool, sizeof(*child_item));
 
9479
              child_item->info.status = svn_wc__db_status_not_present;
 
9480
            }
 
9481
 
 
9482
          child = &child_item->info;
 
9483
 
 
9484
          child->changelist = svn_sqlite__column_text(stmt, 1, result_pool);
 
9485
 
 
9486
          child->props_mod = !svn_sqlite__column_is_null(stmt, 2);
9055
9487
#ifdef HAVE_SYMLINK
9056
 
      if (child->props_mod)
9057
 
        {
9058
 
          svn_error_t *err;
9059
 
          apr_hash_t *properties;
 
9488
          if (child->props_mod)
 
9489
            {
 
9490
              svn_error_t *err;
 
9491
              apr_hash_t *properties;
9060
9492
 
9061
 
          err = svn_sqlite__column_properties(&properties, stmt, 2,
9062
 
                                              scratch_pool, scratch_pool);
9063
 
          if (err)
9064
 
            SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
9065
 
          child->special = (NULL != svn_hash_gets(properties,
9066
 
                                                  SVN_PROP_SPECIAL));
9067
 
        }
 
9493
              err = svn_sqlite__column_properties(&properties, stmt, 2,
 
9494
                                                  scratch_pool, scratch_pool);
 
9495
              if (err)
 
9496
                SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
 
9497
              child->special = (NULL != svn_hash_gets(properties,
 
9498
                                                      SVN_PROP_SPECIAL));
 
9499
            }
9068
9500
#endif
9069
9501
 
9070
 
      child->conflicted = !svn_sqlite__column_is_null(stmt, 3); /* conflict */
9071
 
 
9072
 
      if (child->conflicted)
9073
 
        svn_hash_sets(conflicts, apr_pstrdup(result_pool, name), "");
9074
 
 
9075
 
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
9502
          /* conflict */
 
9503
          child->conflicted = !svn_sqlite__column_is_null(stmt, 3);
 
9504
 
 
9505
          if (child->conflicted)
 
9506
            svn_hash_sets(conflicts, apr_pstrdup(result_pool, name), "");
 
9507
 
 
9508
          SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
9509
        }
 
9510
 
 
9511
      SVN_ERR(svn_sqlite__reset(stmt));
9076
9512
    }
9077
9513
 
9078
 
  SVN_ERR(svn_sqlite__reset(stmt));
9079
 
 
9080
9514
  return SVN_NO_ERROR;
9081
9515
}
9082
9516
 
9085
9519
                              apr_hash_t **conflicts,
9086
9520
                              svn_wc__db_t *db,
9087
9521
                              const char *dir_abspath,
 
9522
                              svn_boolean_t base_tree_only,
9088
9523
                              apr_pool_t *result_pool,
9089
9524
                              apr_pool_t *scratch_pool)
9090
9525
{
9102
9537
 
9103
9538
  SVN_WC__DB_WITH_TXN(
9104
9539
    read_children_info(wcroot, dir_relpath, *conflicts, *nodes,
9105
 
                       result_pool, scratch_pool),
 
9540
                       base_tree_only, result_pool, scratch_pool),
9106
9541
    wcroot);
9107
9542
 
9108
9543
  return SVN_NO_ERROR;
9109
9544
}
9110
9545
 
9111
 
static svn_error_t *
9112
 
db_read_props(apr_hash_t **props,
9113
 
              svn_wc__db_wcroot_t *wcroot,
9114
 
              const char *local_relpath,
9115
 
              apr_pool_t *result_pool,
9116
 
              apr_pool_t *scratch_pool);
9117
 
 
 
9546
/* Implementation of svn_wc__db_read_single_info.
 
9547
 
 
9548
   ### This function is very similar to a lot of code inside
 
9549
   read_children_info, but that performs some tricks to re-use data between
 
9550
   different siblings.
 
9551
 
 
9552
   ### We read the same few NODES records a few times via different helper
 
9553
   functions, so this could be optimized bit, but everything is within
 
9554
   a sqlite transaction and all queries are backed by an index, so generally
 
9555
   everything (including the used indexes) should be in the sqlite page cache
 
9556
   after the first query.
 
9557
*/
9118
9558
static svn_error_t *
9119
9559
read_single_info(const struct svn_wc__db_info_t **info,
9120
9560
                 svn_wc__db_wcroot_t *wcroot,
9121
9561
                 const char *local_relpath,
 
9562
                 svn_boolean_t base_tree_only,
9122
9563
                 apr_pool_t *result_pool,
9123
9564
                 apr_pool_t *scratch_pool)
9124
9565
{
9127
9568
  const svn_checksum_t *checksum;
9128
9569
  const char *original_repos_relpath;
9129
9570
  svn_boolean_t have_work;
 
9571
  apr_hash_t *properties;
9130
9572
 
9131
9573
  mtb = apr_pcalloc(result_pool, sizeof(*mtb));
9132
9574
 
9133
 
  SVN_ERR(read_info(&mtb->status, &mtb->kind, &mtb->revnum,
9134
 
                    &mtb->repos_relpath, &repos_id, &mtb->changed_rev,
9135
 
                    &mtb->changed_date, &mtb->changed_author, &mtb->depth,
9136
 
                    &checksum, NULL, &original_repos_relpath, NULL, NULL,
9137
 
                    &mtb->lock, &mtb->recorded_size, &mtb->recorded_time,
9138
 
                    &mtb->changelist, &mtb->conflicted, &mtb->op_root,
9139
 
                    &mtb->had_props, &mtb->props_mod, &mtb->have_base,
9140
 
                    &mtb->have_more_work, &have_work,
9141
 
                    wcroot, local_relpath,
9142
 
                    result_pool, scratch_pool));
 
9575
  if (!base_tree_only)
 
9576
    SVN_ERR(read_info(&mtb->status, &mtb->kind, &mtb->revnum,
 
9577
                      &mtb->repos_relpath, &repos_id, &mtb->changed_rev,
 
9578
                      &mtb->changed_date, &mtb->changed_author, &mtb->depth,
 
9579
                      &checksum, NULL, &original_repos_relpath, NULL, NULL,
 
9580
                      &mtb->lock, &mtb->recorded_size, &mtb->recorded_time,
 
9581
                      &mtb->changelist, &mtb->conflicted, &mtb->op_root,
 
9582
                      &mtb->had_props, &mtb->props_mod, &mtb->have_base,
 
9583
                      &mtb->have_more_work, &have_work,
 
9584
                      wcroot, local_relpath, result_pool, scratch_pool));
 
9585
  else
 
9586
    {
 
9587
      svn_boolean_t update_root;
 
9588
 
 
9589
      have_work = FALSE;
 
9590
      original_repos_relpath = NULL;
 
9591
 
 
9592
      SVN_ERR(svn_wc__db_base_get_info_internal(
 
9593
                  &mtb->status, &mtb->kind, &mtb->revnum, &mtb->repos_relpath,
 
9594
                  &repos_id, &mtb->changed_rev, &mtb->changed_date,
 
9595
                  &mtb->changed_author, &mtb->depth, &checksum, NULL,
 
9596
                  &mtb->lock, &mtb->had_props, &properties, &update_root,
 
9597
                  wcroot, local_relpath, scratch_pool, scratch_pool));
 
9598
 
 
9599
      mtb->have_base = TRUE;
 
9600
      mtb->file_external = (update_root && mtb->kind == svn_node_file);
 
9601
    }
9143
9602
 
9144
9603
  /* Query the same rows in the database again for move information */
9145
9604
  if (have_work && (mtb->have_base || mtb->have_more_work))
9146
9605
    {
9147
9606
      svn_sqlite__stmt_t *stmt;
9148
9607
      svn_boolean_t have_row;
9149
 
      const char *cur_relpath = NULL;
9150
 
      int cur_op_depth;
9151
9608
 
9152
9609
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
9153
9610
                                        STMT_SELECT_MOVED_TO_NODE));
9160
9617
          struct svn_wc__db_moved_to_info_t *move;
9161
9618
          int op_depth = svn_sqlite__column_int(stmt, 0);
9162
9619
          const char *moved_to_relpath = svn_sqlite__column_text(stmt, 1, NULL);
 
9620
          const char *cur_relpath;
9163
9621
 
9164
9622
          move = apr_pcalloc(result_pool, sizeof(*move));
9165
9623
          move->moved_to_abspath = svn_dirent_join(wcroot->abspath,
9166
9624
                                                   moved_to_relpath,
9167
9625
                                                   result_pool);
9168
9626
 
9169
 
          if (!cur_relpath)
9170
 
            {
9171
 
              cur_relpath = local_relpath;
9172
 
              cur_op_depth = relpath_depth(cur_relpath);
9173
 
            }
9174
 
          while (cur_op_depth > op_depth)
9175
 
            {
9176
 
              cur_relpath = svn_relpath_dirname(cur_relpath, scratch_pool);
9177
 
              cur_op_depth--;
9178
 
            }
 
9627
          cur_relpath = svn_relpath_prefix(local_relpath, op_depth,
 
9628
                                           scratch_pool);
 
9629
 
9179
9630
          move->shadow_op_root_abspath = svn_dirent_join(wcroot->abspath,
9180
9631
                                                         cur_relpath,
9181
9632
                                                         result_pool);
9192
9643
  /* Maybe we have to get some shadowed lock from BASE to make our test suite
9193
9644
     happy... (It might be completely unrelated, but...)
9194
9645
     This queries the same BASE row again, joined to the lock table */
9195
 
  if (mtb->have_base && (have_work || mtb->kind == svn_node_file))
 
9646
  if (!base_tree_only && mtb->have_base
 
9647
      && (have_work || mtb->kind == svn_node_file))
9196
9648
    {
9197
9649
      svn_boolean_t update_root;
9198
9650
      svn_wc__db_lock_t **lock_arg = NULL;
9225
9677
 
9226
9678
#ifdef HAVE_SYMLINK
9227
9679
  if (mtb->kind == svn_node_file
9228
 
      && (mtb->had_props || mtb->props_mod))
 
9680
      && (mtb->had_props || mtb->props_mod
 
9681
          || (base_tree_only && properties)))
9229
9682
    {
9230
 
      apr_hash_t *properties;
9231
 
 
9232
 
      if (mtb->props_mod)
9233
 
        SVN_ERR(db_read_props(&properties,
9234
 
                              wcroot, local_relpath,
9235
 
                              scratch_pool, scratch_pool));
9236
 
      else
9237
 
        SVN_ERR(db_read_pristine_props(&properties, wcroot, local_relpath,
9238
 
                                       TRUE /* deleted_ok */,
9239
 
                                       scratch_pool, scratch_pool));
 
9683
      if (!base_tree_only)
 
9684
        {
 
9685
          if (mtb->props_mod)
 
9686
            SVN_ERR(svn_wc__db_read_props_internal(&properties,
 
9687
                                                   wcroot, local_relpath,
 
9688
                                                   scratch_pool, scratch_pool));
 
9689
          else
 
9690
            SVN_ERR(db_read_pristine_props(&properties, wcroot, local_relpath,
 
9691
                                           TRUE /* deleted_ok */,
 
9692
                                           scratch_pool, scratch_pool));
 
9693
        }
9240
9694
 
9241
9695
      mtb->special = (NULL != svn_hash_gets(properties, SVN_PROP_SPECIAL));
9242
9696
    }
9246
9700
  mtb->copied = (original_repos_relpath != NULL);
9247
9701
 
9248
9702
  SVN_ERR(svn_wc__db_fetch_repos_info(&mtb->repos_root_url, &mtb->repos_uuid,
9249
 
                                      wcroot->sdb, repos_id, result_pool));
 
9703
                                      wcroot, repos_id, result_pool));
 
9704
 
 
9705
  if (!base_tree_only && mtb->kind == svn_node_dir)
 
9706
    SVN_ERR(is_wclocked(&mtb->locked, wcroot, local_relpath, scratch_pool));
9250
9707
 
9251
9708
  if (mtb->kind == svn_node_dir)
9252
 
    SVN_ERR(is_wclocked(&mtb->locked, wcroot, local_relpath, scratch_pool));
 
9709
    mtb->has_descendants = TRUE;
 
9710
  else
 
9711
    SVN_ERR(find_conflict_descendants(&mtb->has_descendants,
 
9712
                                      wcroot, local_relpath, scratch_pool));
9253
9713
 
9254
9714
  *info = mtb;
9255
9715
 
9260
9720
svn_wc__db_read_single_info(const struct svn_wc__db_info_t **info,
9261
9721
                            svn_wc__db_t *db,
9262
9722
                            const char *local_abspath,
 
9723
                            svn_boolean_t base_tree_only,
9263
9724
                            apr_pool_t *result_pool,
9264
9725
                            apr_pool_t *scratch_pool)
9265
9726
{
9274
9735
  VERIFY_USABLE_WCROOT(wcroot);
9275
9736
 
9276
9737
  SVN_WC__DB_WITH_TXN(read_single_info(info, wcroot, local_relpath,
 
9738
                                       base_tree_only,
9277
9739
                                       result_pool, scratch_pool),
9278
9740
                      wcroot);
9279
9741
 
9443
9905
}
9444
9906
 
9445
9907
svn_error_t *
9446
 
svn_wc__db_read_children_walker_info(apr_hash_t **nodes,
 
9908
svn_wc__db_read_children_walker_info(const apr_array_header_t **items,
9447
9909
                                     svn_wc__db_t *db,
9448
9910
                                     const char *dir_abspath,
9449
9911
                                     apr_pool_t *result_pool,
9453
9915
  const char *dir_relpath;
9454
9916
  svn_sqlite__stmt_t *stmt;
9455
9917
  svn_boolean_t have_row;
 
9918
  apr_array_header_t *nodes;
9456
9919
 
9457
9920
  SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
9458
9921
 
9466
9929
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, dir_relpath));
9467
9930
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
9468
9931
 
9469
 
  *nodes = apr_hash_make(result_pool);
 
9932
  nodes = apr_array_make(result_pool, 16,
 
9933
                          sizeof(struct svn_wc__db_walker_info_t *));
9470
9934
  while (have_row)
9471
9935
    {
9472
9936
      struct svn_wc__db_walker_info_t *child;
9473
9937
      const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
9474
 
      const char *name = svn_relpath_basename(child_relpath, NULL);
 
9938
      const char *name = svn_relpath_basename(child_relpath, result_pool);
9475
9939
      int op_depth = svn_sqlite__column_int(stmt, 1);
9476
9940
      svn_error_t *err;
9477
9941
 
9478
9942
      child = apr_palloc(result_pool, sizeof(*child));
 
9943
      child->name = name;
9479
9944
      child->status = svn_sqlite__column_token(stmt, 2, presence_map);
9480
9945
      if (op_depth > 0)
9481
9946
        {
9484
9949
            SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
9485
9950
        }
9486
9951
      child->kind = svn_sqlite__column_token(stmt, 3, kind_map);
9487
 
      svn_hash_sets(*nodes, apr_pstrdup(result_pool, name), child);
 
9952
 
 
9953
      APR_ARRAY_PUSH(nodes, struct svn_wc__db_walker_info_t *) = child;
9488
9954
 
9489
9955
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
9490
9956
    }
9491
9957
 
9492
9958
  SVN_ERR(svn_sqlite__reset(stmt));
9493
9959
 
 
9960
  *items = nodes;
 
9961
 
9494
9962
  return SVN_NO_ERROR;
9495
9963
}
9496
9964
 
9545
10013
 
9546
10014
  if (have_row)
9547
10015
    {
9548
 
      if (!err && sha1_checksum)
 
10016
      if (sha1_checksum)
9549
10017
        err = svn_sqlite__column_checksum(sha1_checksum, stmt, 6, result_pool);
9550
10018
 
9551
10019
      if (!err && pristine_props)
9574
10042
 
9575
10043
 
9576
10044
 
9577
 
/* The body of svn_wc__db_read_url().
 
10045
/* The body of svn_wc__db_read_repos_info().
9578
10046
 */
9579
10047
static svn_error_t *
9580
 
read_url_txn(const char **url,
9581
 
             svn_wc__db_wcroot_t *wcroot,
9582
 
             const char *local_relpath,
9583
 
             apr_pool_t *result_pool,
9584
 
             apr_pool_t *scratch_pool)
 
10048
db_read_repos_info(svn_revnum_t *revision,
 
10049
                   const char **repos_relpath,
 
10050
                   apr_int64_t *repos_id,
 
10051
                   svn_wc__db_wcroot_t *wcroot,
 
10052
                   const char *local_relpath,
 
10053
                   apr_pool_t *result_pool,
 
10054
                   apr_pool_t *scratch_pool)
9585
10055
{
9586
10056
  svn_wc__db_status_t status;
9587
 
  const char *repos_relpath;
9588
 
  const char *repos_root_url;
9589
 
  apr_int64_t repos_id;
9590
 
  svn_boolean_t have_base;
9591
10057
 
9592
 
  SVN_ERR(read_info(&status, NULL, NULL, &repos_relpath, &repos_id, NULL,
 
10058
  SVN_ERR(read_info(&status, NULL, revision, repos_relpath, repos_id, NULL,
9593
10059
                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
9594
10060
                    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
9595
 
                    &have_base, NULL, NULL,
9596
 
                    wcroot, local_relpath, scratch_pool, scratch_pool));
 
10061
                    NULL, NULL, NULL,
 
10062
                    wcroot, local_relpath, result_pool, scratch_pool));
9597
10063
 
9598
 
  if (repos_relpath == NULL)
 
10064
  if ((repos_relpath && !*repos_relpath)
 
10065
      || (repos_id && *repos_id == INVALID_REPOS_ID))
9599
10066
    {
9600
10067
      if (status == svn_wc__db_status_added)
9601
10068
        {
9602
 
          SVN_ERR(scan_addition(NULL, NULL, &repos_relpath, &repos_id, NULL,
 
10069
          SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL,
9603
10070
                                NULL, NULL, NULL, NULL, NULL,
9604
10071
                                wcroot, local_relpath,
9605
 
                                scratch_pool, scratch_pool));
 
10072
                                result_pool, scratch_pool));
9606
10073
        }
9607
10074
      else if (status == svn_wc__db_status_deleted)
9608
10075
        {
9609
10076
          const char *base_del_relpath;
9610
10077
          const char *work_del_relpath;
9611
10078
 
9612
 
          SVN_ERR(scan_deletion_txn(&base_del_relpath, NULL,
9613
 
                                    &work_del_relpath,
9614
 
                                    NULL, wcroot,
9615
 
                                    local_relpath,
9616
 
                                    scratch_pool,
9617
 
                                    scratch_pool));
9618
 
 
9619
 
          if (base_del_relpath)
9620
 
            {
9621
 
              SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
9622
 
                                                        &repos_relpath,
9623
 
                                                        &repos_id,
9624
 
                                                        NULL, NULL, NULL,
9625
 
                                                        NULL, NULL, NULL,
9626
 
                                                        NULL, NULL, NULL, NULL,
9627
 
                                                        wcroot,
9628
 
                                                        base_del_relpath,
9629
 
                                                        scratch_pool,
9630
 
                                                        scratch_pool));
9631
 
 
9632
 
              repos_relpath = svn_relpath_join(
9633
 
                                    repos_relpath,
9634
 
                                    svn_dirent_skip_ancestor(base_del_relpath,
9635
 
                                                             local_relpath),
9636
 
                                    scratch_pool);
9637
 
            }
9638
 
          else
 
10079
          SVN_ERR(scan_deletion(&base_del_relpath, NULL,
 
10080
                                &work_del_relpath,
 
10081
                                NULL, wcroot,
 
10082
                                local_relpath,
 
10083
                                scratch_pool,
 
10084
                                scratch_pool));
 
10085
 
 
10086
          if (work_del_relpath)
9639
10087
            {
9640
10088
              /* The parent of the WORKING delete, must be an addition */
9641
10089
              const char *work_relpath = NULL;
9648
10096
              work_relpath = svn_relpath_dirname(work_del_relpath,
9649
10097
                                                 scratch_pool);
9650
10098
 
9651
 
              SVN_ERR(scan_addition(NULL, NULL, &repos_relpath, &repos_id,
 
10099
              SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id,
9652
10100
                                    NULL, NULL, NULL, NULL, NULL, NULL,
9653
10101
                                    wcroot, work_relpath,
9654
10102
                                    scratch_pool, scratch_pool));
9655
10103
 
9656
 
              repos_relpath = svn_relpath_join(
9657
 
                                    repos_relpath,
 
10104
              if (repos_relpath)
 
10105
                *repos_relpath = svn_relpath_join(
 
10106
                                    *repos_relpath,
9658
10107
                                    svn_dirent_skip_ancestor(work_relpath,
9659
10108
                                                             local_relpath),
9660
 
                                    scratch_pool);
 
10109
                                    result_pool);
 
10110
            }
 
10111
          else
 
10112
            {
 
10113
              SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, revision,
 
10114
                                                        repos_relpath,
 
10115
                                                        repos_id,
 
10116
                                                        NULL, NULL, NULL,
 
10117
                                                        NULL, NULL, NULL,
 
10118
                                                        NULL, NULL, NULL, NULL,
 
10119
                                                        wcroot,
 
10120
                                                        base_del_relpath,
 
10121
                                                        scratch_pool,
 
10122
                                                        scratch_pool));
 
10123
 
 
10124
              if (repos_relpath)
 
10125
                *repos_relpath = svn_relpath_join(
 
10126
                                    *repos_relpath,
 
10127
                                    svn_dirent_skip_ancestor(base_del_relpath,
 
10128
                                                             local_relpath),
 
10129
                                    result_pool);
9661
10130
            }
9662
10131
        }
9663
10132
      else if (status == svn_wc__db_status_excluded)
9664
10133
        {
9665
10134
          const char *parent_relpath;
9666
10135
          const char *name;
9667
 
          const char *url2;
9668
 
 
9669
 
          /* Set 'url' to the *full URL* of the parent WC dir,
9670
 
           * and 'name' to the *single path component* that is the
9671
 
           * basename of this WC directory, so that joining them will result
9672
 
           * in the correct full URL. */
 
10136
 
 
10137
          /* A BASE excluded would have had repository information, so
 
10138
             we have a working exclude, which must be below an addition */
 
10139
 
9673
10140
          svn_relpath_split(&parent_relpath, &name, local_relpath,
9674
10141
                            scratch_pool);
9675
 
          SVN_ERR(read_url_txn(&url2, wcroot, parent_relpath,
9676
 
                               scratch_pool, scratch_pool));
 
10142
          SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL,
 
10143
                                NULL, NULL, NULL, NULL, NULL,
 
10144
                                wcroot, parent_relpath,
 
10145
                                scratch_pool, scratch_pool));
9677
10146
 
9678
 
          *url = svn_path_url_add_component2(url2, name, result_pool);
 
10147
          if (repos_relpath)
 
10148
            *repos_relpath = svn_relpath_join(*repos_relpath, name,
 
10149
                                              result_pool);
9679
10150
 
9680
10151
          return SVN_NO_ERROR;
9681
10152
        }
9687
10158
        }
9688
10159
    }
9689
10160
 
9690
 
  SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, NULL, wcroot->sdb,
9691
 
                                      repos_id, scratch_pool));
9692
 
 
9693
 
  SVN_ERR_ASSERT(repos_root_url != NULL && repos_relpath != NULL);
9694
 
  *url = svn_path_url_add_component2(repos_root_url, repos_relpath,
9695
 
                                     result_pool);
9696
 
 
9697
10161
  return SVN_NO_ERROR;
9698
10162
}
9699
10163
 
9700
10164
 
9701
10165
svn_error_t *
9702
 
svn_wc__db_read_url(const char **url,
9703
 
                    svn_wc__db_t *db,
9704
 
                    const char *local_abspath,
9705
 
                    apr_pool_t *result_pool,
9706
 
                    apr_pool_t *scratch_pool)
 
10166
svn_wc__db_read_repos_info(svn_revnum_t *revision,
 
10167
                           const char **repos_relpath,
 
10168
                           const char **repos_root_url,
 
10169
                           const char **repos_uuid,
 
10170
                           svn_wc__db_t *db,
 
10171
                           const char *local_abspath,
 
10172
                           apr_pool_t *result_pool,
 
10173
                           apr_pool_t *scratch_pool)
9707
10174
{
9708
10175
  svn_wc__db_wcroot_t *wcroot;
9709
10176
  const char *local_relpath;
 
10177
  apr_int64_t repos_id = INVALID_REPOS_ID;
9710
10178
 
9711
10179
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
9712
10180
 
9715
10183
                                                scratch_pool, scratch_pool));
9716
10184
  VERIFY_USABLE_WCROOT(wcroot);
9717
10185
 
9718
 
  SVN_WC__DB_WITH_TXN(read_url_txn(url, wcroot, local_relpath,
9719
 
                                   result_pool, scratch_pool),
9720
 
                      wcroot);
 
10186
  SVN_WC__DB_WITH_TXN4(db_read_repos_info(revision, repos_relpath,
 
10187
                                          (repos_root_url || repos_uuid)
 
10188
                                            ? &repos_id : NULL,
 
10189
                                          wcroot, local_relpath,
 
10190
                                          result_pool, scratch_pool),
 
10191
                       svn_wc__db_fetch_repos_info(repos_root_url,
 
10192
                                                   repos_uuid,
 
10193
                                                   wcroot, repos_id,
 
10194
                                                   result_pool),
 
10195
                       SVN_NO_ERROR, SVN_NO_ERROR,
 
10196
                       wcroot);
9721
10197
 
9722
10198
  return SVN_NO_ERROR;
9723
10199
}
9861
10337
 
9862
10338
/* Helper for svn_wc__db_read_props().
9863
10339
 */
9864
 
static svn_error_t *
9865
 
db_read_props(apr_hash_t **props,
9866
 
              svn_wc__db_wcroot_t *wcroot,
9867
 
              const char *local_relpath,
9868
 
              apr_pool_t *result_pool,
9869
 
              apr_pool_t *scratch_pool)
 
10340
svn_error_t *
 
10341
svn_wc__db_read_props_internal(apr_hash_t **props,
 
10342
                               svn_wc__db_wcroot_t *wcroot,
 
10343
                               const char *local_relpath,
 
10344
                               apr_pool_t *result_pool,
 
10345
                               apr_pool_t *scratch_pool)
9870
10346
{
9871
10347
  svn_sqlite__stmt_t *stmt;
9872
10348
  svn_boolean_t have_row;
9923
10399
                              local_abspath, scratch_pool, scratch_pool));
9924
10400
  VERIFY_USABLE_WCROOT(wcroot);
9925
10401
 
9926
 
  SVN_WC__DB_WITH_TXN(db_read_props(props, wcroot, local_relpath,
9927
 
                                    result_pool, scratch_pool),
 
10402
  SVN_WC__DB_WITH_TXN(svn_wc__db_read_props_internal(props, wcroot,
 
10403
                                                     local_relpath,
 
10404
                                                     result_pool,
 
10405
                                                     scratch_pool),
9928
10406
                      wcroot);
9929
10407
 
9930
10408
  return SVN_NO_ERROR;
10155
10633
       hi;
10156
10634
       hi = apr_hash_next(hi))
10157
10635
    {
10158
 
      const char *ipropname = svn__apr_hash_index_key(hi);
 
10636
      const char *ipropname = apr_hash_this_key(hi);
10159
10637
 
10160
10638
      if (strcmp(ipropname, propname) != 0)
10161
10639
        svn_hash_sets(prop_hash, ipropname, NULL);
10329
10807
 
10330
10808
                  iprop_elt->prop_hash = node_props;
10331
10809
                  /* Build the output array in depth-first order. */
10332
 
                  svn_sort__array_insert(&iprop_elt, iprops, 0);
 
10810
                  svn_sort__array_insert(iprops, &iprop_elt, 0);
10333
10811
                }
10334
10812
            }
10335
10813
        }
10365
10843
 
10366
10844
          /* If we didn't filter everything then keep this iprop. */
10367
10845
          if (apr_hash_count(cached_iprop->prop_hash))
10368
 
            svn_sort__array_insert(&cached_iprop, iprops, 0);
 
10846
            svn_sort__array_insert(iprops, &cached_iprop, 0);
10369
10847
        }
10370
10848
    }
10371
10849
 
10479
10957
           hi;
10480
10958
           hi = apr_hash_next(hi))
10481
10959
        {
10482
 
          const char *child_abspath = svn__apr_hash_index_key(hi);
 
10960
          const char *child_abspath = apr_hash_this_key(hi);
10483
10961
          const char *child_relpath;
10484
10962
          svn_node_kind_t child_kind;
10485
10963
 
10557
11035
                                             scratch_pool, scratch_pool));
10558
11036
  VERIFY_USABLE_WCROOT(wcroot);
10559
11037
 
10560
 
  return gather_children2(children, wcroot, local_relpath,
10561
 
                          result_pool, scratch_pool);
 
11038
  return svn_error_trace(
 
11039
          gather_children(children, wcroot, local_relpath,
 
11040
                          STMT_SELECT_WORKING_CHILDREN, -1,
 
11041
                          result_pool, scratch_pool));
 
11042
}
 
11043
 
 
11044
svn_error_t *
 
11045
svn_wc__db_base_read_not_present_children(
 
11046
                                const apr_array_header_t **children,
 
11047
                                svn_wc__db_t *db,
 
11048
                                const char *local_abspath,
 
11049
                                apr_pool_t *result_pool,
 
11050
                                apr_pool_t *scratch_pool)
 
11051
{
 
11052
  svn_wc__db_wcroot_t *wcroot;
 
11053
  const char *local_relpath;
 
11054
 
 
11055
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
11056
 
 
11057
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
 
11058
                                             local_abspath,
 
11059
                                             scratch_pool, scratch_pool));
 
11060
  VERIFY_USABLE_WCROOT(wcroot);
 
11061
 
 
11062
  return svn_error_trace(
 
11063
          gather_children(children, wcroot, local_relpath,
 
11064
                          STMT_SELECT_BASE_NOT_PRESENT_CHILDREN, -1,
 
11065
                          result_pool, scratch_pool));
10562
11066
}
10563
11067
 
10564
11068
/* Helper for svn_wc__db_node_check_replace().
10745
11249
  VERIFY_USABLE_WCROOT(wcroot);
10746
11250
 
10747
11251
  return gather_children(children, wcroot, local_relpath,
 
11252
                         STMT_SELECT_NODE_CHILDREN, -1,
10748
11253
                         result_pool, scratch_pool);
10749
11254
}
10750
11255
 
10751
11256
 
10752
 
/* */
 
11257
/* Implementation of svn_wc__db_global_relocate */
10753
11258
static svn_error_t *
10754
11259
relocate_txn(svn_wc__db_wcroot_t *wcroot,
10755
11260
             const char *local_relpath,
10756
11261
             const char *repos_root_url,
10757
 
             const char *repos_uuid,
10758
 
             svn_boolean_t have_base_node,
10759
 
             apr_int64_t old_repos_id,
10760
11262
             apr_pool_t *scratch_pool)
10761
11263
{
10762
11264
  svn_sqlite__stmt_t *stmt;
10763
11265
  apr_int64_t new_repos_id;
10764
 
 
10765
 
  /* This function affects all the children of the given local_relpath,
10766
 
     but the way that it does this is through the repos inheritance mechanism.
10767
 
     So, we only need to rewrite the repos_id of the given local_relpath,
10768
 
     as well as any children with a non-null repos_id, as well as various
10769
 
     repos_id fields in the locks and working_node tables.
10770
 
   */
10771
 
 
10772
 
  /* Get the repos_id for the new repository. */
10773
 
  SVN_ERR(create_repos_id(&new_repos_id, repos_root_url, repos_uuid,
10774
 
                          wcroot->sdb, scratch_pool));
10775
 
 
10776
 
  /* Set the (base and working) repos_ids and clear the dav_caches */
10777
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
10778
 
                                    STMT_RECURSIVE_UPDATE_NODE_REPO));
10779
 
  SVN_ERR(svn_sqlite__bindf(stmt, "isii", wcroot->wc_id, local_relpath,
10780
 
                            old_repos_id, new_repos_id));
10781
 
  SVN_ERR(svn_sqlite__step_done(stmt));
10782
 
 
10783
 
  if (have_base_node)
10784
 
    {
10785
 
      /* Update any locks for the root or its children. */
10786
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
10787
 
                                        STMT_UPDATE_LOCK_REPOS_ID));
10788
 
      SVN_ERR(svn_sqlite__bindf(stmt, "ii", old_repos_id, new_repos_id));
10789
 
      SVN_ERR(svn_sqlite__step_done(stmt));
10790
 
    }
10791
 
 
10792
 
  return SVN_NO_ERROR;
10793
 
}
10794
 
 
10795
 
 
10796
 
svn_error_t *
10797
 
svn_wc__db_global_relocate(svn_wc__db_t *db,
10798
 
                           const char *local_dir_abspath,
10799
 
                           const char *repos_root_url,
10800
 
                           apr_pool_t *scratch_pool)
10801
 
{
10802
 
  svn_wc__db_wcroot_t *wcroot;
10803
 
  const char *local_relpath;
10804
11266
  const char *local_dir_relpath;
10805
11267
  svn_wc__db_status_t status;
10806
11268
  const char *repos_uuid;
10807
11269
  svn_boolean_t have_base_node;
10808
11270
  apr_int64_t old_repos_id;
10809
11271
 
10810
 
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_dir_abspath));
10811
 
  /* ### assert that we were passed a directory?  */
10812
 
 
10813
 
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_dir_relpath,
10814
 
                           db, local_dir_abspath, scratch_pool, scratch_pool));
10815
 
  VERIFY_USABLE_WCROOT(wcroot);
10816
 
  local_relpath = local_dir_relpath;
 
11272
  local_dir_relpath = local_relpath;
10817
11273
 
10818
11274
  SVN_ERR(read_info(&status,
10819
11275
                    NULL, NULL, NULL, &old_repos_id,
10852
11308
        {
10853
11309
          const char *work_del_relpath;
10854
11310
 
10855
 
          SVN_ERR(scan_deletion_txn(NULL, NULL,
10856
 
                                    &work_del_relpath, NULL,
10857
 
                                    wcroot, local_dir_relpath,
10858
 
                                    scratch_pool,
10859
 
                                    scratch_pool));
 
11311
          SVN_ERR(scan_deletion(NULL, NULL,
 
11312
                                &work_del_relpath, NULL,
 
11313
                                wcroot, local_dir_relpath,
 
11314
                                scratch_pool,
 
11315
                                scratch_pool));
10860
11316
          if (work_del_relpath)
10861
11317
            {
10862
11318
              /* Deleted within a copy/move */
10884
11340
                                                  scratch_pool, scratch_pool));
10885
11341
    }
10886
11342
 
10887
 
  SVN_ERR(svn_wc__db_fetch_repos_info(NULL, &repos_uuid, wcroot->sdb,
 
11343
  SVN_ERR(svn_wc__db_fetch_repos_info(NULL, &repos_uuid, wcroot,
10888
11344
                                      old_repos_id, scratch_pool));
10889
 
  SVN_ERR_ASSERT(repos_uuid);
 
11345
  SVN_ERR_ASSERT(repos_uuid);  /* This function affects all the children of the given local_relpath,
 
11346
     but the way that it does this is through the repos inheritance mechanism.
 
11347
     So, we only need to rewrite the repos_id of the given local_relpath,
 
11348
     as well as any children with a non-null repos_id, as well as various
 
11349
     repos_id fields in the locks and working_node tables.
 
11350
   */
 
11351
 
 
11352
  /* Get the repos_id for the new repository. */
 
11353
  SVN_ERR(create_repos_id(&new_repos_id, repos_root_url, repos_uuid,
 
11354
                          wcroot->sdb, scratch_pool));
 
11355
 
 
11356
  /* Set the (base and working) repos_ids and clear the dav_caches */
 
11357
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
11358
                                    STMT_RECURSIVE_UPDATE_NODE_REPO));
 
11359
  SVN_ERR(svn_sqlite__bindf(stmt, "isii", wcroot->wc_id, local_relpath,
 
11360
                            old_repos_id, new_repos_id));
 
11361
  SVN_ERR(svn_sqlite__step_done(stmt));
 
11362
 
 
11363
  if (have_base_node)
 
11364
    {
 
11365
      /* Update any locks for the root or its children. */
 
11366
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
11367
                                        STMT_UPDATE_LOCK_REPOS_ID));
 
11368
      SVN_ERR(svn_sqlite__bindf(stmt, "ii", old_repos_id, new_repos_id));
 
11369
      SVN_ERR(svn_sqlite__step_done(stmt));
 
11370
    }
 
11371
 
 
11372
  return SVN_NO_ERROR;
 
11373
}
 
11374
 
 
11375
 
 
11376
svn_error_t *
 
11377
svn_wc__db_global_relocate(svn_wc__db_t *db,
 
11378
                           const char *local_dir_abspath,
 
11379
                           const char *repos_root_url,
 
11380
                           apr_pool_t *scratch_pool)
 
11381
{
 
11382
  svn_wc__db_wcroot_t *wcroot;
 
11383
  const char *local_relpath;
 
11384
 
 
11385
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_dir_abspath));
 
11386
  /* ### assert that we were passed a directory?  */
 
11387
 
 
11388
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
 
11389
                           db, local_dir_abspath, scratch_pool, scratch_pool));
 
11390
  VERIFY_USABLE_WCROOT(wcroot);
10890
11391
 
10891
11392
  SVN_WC__DB_WITH_TXN(
10892
 
    relocate_txn(wcroot, local_relpath, repos_root_url, repos_uuid,
10893
 
                 have_base_node, old_repos_id, scratch_pool),
 
11393
    relocate_txn(wcroot, local_relpath, repos_root_url, scratch_pool),
10894
11394
    wcroot);
10895
11395
 
 
11396
  SVN_ERR(flush_entries(wcroot, local_dir_abspath, svn_depth_infinity,
 
11397
                        scratch_pool));
 
11398
 
10896
11399
  return SVN_NO_ERROR;
10897
11400
}
10898
11401
 
10979
11482
  return svn_error_trace(svn_sqlite__reset(stmt));
10980
11483
}
10981
11484
 
 
11485
static svn_error_t *
 
11486
moved_descendant_collect(apr_hash_t **map,
 
11487
                        svn_wc__db_wcroot_t *wcroot,
 
11488
                        const char *local_relpath,
 
11489
                        int op_depth,
 
11490
                        apr_pool_t *result_pool,
 
11491
                        apr_pool_t *scratch_pool)
 
11492
{
 
11493
  svn_sqlite__stmt_t *stmt;
 
11494
  svn_boolean_t have_row;
 
11495
 
 
11496
  *map = NULL;
 
11497
 
 
11498
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
11499
                                    STMT_SELECT_MOVED_DESCENDANTS_SRC));
 
11500
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
 
11501
                                         local_relpath,
 
11502
                                         op_depth));
 
11503
 
 
11504
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
11505
  if (! have_row)
 
11506
    return svn_error_trace(svn_sqlite__reset(stmt));
 
11507
 
 
11508
  /* Find all moved descendants. Key them on target, because that is
 
11509
     always unique */
 
11510
  while (have_row)
 
11511
    {
 
11512
      const char *src_relpath = svn_sqlite__column_text(stmt, 1, result_pool);
 
11513
      const char *to_relpath = svn_sqlite__column_text(stmt, 4, result_pool);
 
11514
 
 
11515
      if (!*map)
 
11516
        *map = apr_hash_make(result_pool);
 
11517
 
 
11518
      svn_hash_sets(*map, to_relpath, src_relpath);
 
11519
 
 
11520
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
11521
    }
 
11522
  SVN_ERR(svn_sqlite__reset(stmt));
 
11523
 
 
11524
  return SVN_NO_ERROR;
 
11525
}
 
11526
 
10982
11527
/* Helper for svn_wc__db_global_commit()
10983
11528
 
10984
11529
   Makes local_relpath and all its descendants at the same op-depth represent
10990
11535
   Assumptions:
10991
11536
     * local_relpath is not the working copy root (can't be moved)
10992
11537
     * repos_relpath is not the repository root (can't be moved)
10993
 
   */
 
11538
 */
10994
11539
static svn_error_t *
10995
11540
moved_descendant_commit(svn_wc__db_wcroot_t *wcroot,
10996
11541
                        const char *local_relpath,
10997
 
                        int op_depth,
10998
11542
                        apr_int64_t repos_id,
10999
11543
                        const char *repos_relpath,
11000
11544
                        svn_revnum_t revision,
 
11545
                        apr_hash_t *children,
11001
11546
                        apr_pool_t *scratch_pool)
11002
11547
{
11003
 
  apr_hash_t *children;
11004
11548
  apr_pool_t *iterpool;
11005
11549
  svn_sqlite__stmt_t *stmt;
11006
 
  svn_boolean_t have_row;
11007
11550
  apr_hash_index_t *hi;
11008
11551
 
11009
11552
  SVN_ERR_ASSERT(*local_relpath != '\0'
11010
11553
                 && *repos_relpath != '\0');
11011
11554
 
11012
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
11013
 
                                    STMT_SELECT_MOVED_DESCENDANTS));
11014
 
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
11015
 
                                         local_relpath,
11016
 
                                         op_depth));
11017
 
 
11018
 
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
11019
 
  if (! have_row)
11020
 
    return svn_error_trace(svn_sqlite__reset(stmt));
11021
 
 
11022
 
  children = apr_hash_make(scratch_pool);
11023
 
 
11024
 
  /* First, obtain all moved children */
11025
 
  /* To keep error handling simple, first cache them in a hashtable */
11026
 
  while (have_row)
11027
 
    {
11028
 
      const char *src_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
11029
 
      const char *to_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool);
11030
 
 
11031
 
      svn_hash_sets(children, src_relpath, to_relpath);
11032
 
 
11033
 
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
11034
 
    }
11035
 
  SVN_ERR(svn_sqlite__reset(stmt));
 
11555
  if (!children)
 
11556
    return SVN_NO_ERROR;
11036
11557
 
11037
11558
  /* Then update them */
11038
11559
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
11041
11562
  iterpool = svn_pool_create(scratch_pool);
11042
11563
  for (hi = apr_hash_first(scratch_pool, children); hi; hi = apr_hash_next(hi))
11043
11564
    {
11044
 
      const char *src_relpath = svn__apr_hash_index_key(hi);
11045
 
      const char *to_relpath = svn__apr_hash_index_val(hi);
 
11565
      const char *src_relpath = apr_hash_this_val(hi);
 
11566
      const char *to_relpath = apr_hash_this_key(hi);
11046
11567
      const char *new_repos_relpath;
11047
11568
      int to_op_depth = relpath_depth(to_relpath);
11048
11569
      int affected;
 
11570
      apr_hash_t *map;
11049
11571
 
11050
11572
      svn_pool_clear(iterpool);
11051
11573
 
11072
11594
      SVN_ERR_ASSERT(affected >= 1); /* If this fails there is no move dest */
11073
11595
#endif
11074
11596
 
11075
 
      SVN_ERR(moved_descendant_commit(wcroot, to_relpath, to_op_depth,
 
11597
      SVN_ERR(moved_descendant_collect(&map, wcroot, to_relpath, to_op_depth,
 
11598
                                       iterpool, iterpool));
 
11599
      SVN_ERR(moved_descendant_commit(wcroot, to_relpath,
11076
11600
                                      repos_id, new_repos_relpath, revision,
11077
 
                                      iterpool));
 
11601
                                      map, iterpool));
11078
11602
    }
11079
11603
 
11080
11604
  svn_pool_destroy(iterpool);
11133
11657
            apr_time_t changed_date,
11134
11658
            const char *changed_author,
11135
11659
            const svn_checksum_t *new_checksum,
11136
 
            const apr_array_header_t *new_children,
11137
11660
            apr_hash_t *new_dav_cache,
11138
11661
            svn_boolean_t keep_changelist,
11139
11662
            svn_boolean_t no_unlock,
11155
11678
  const char *repos_relpath;
11156
11679
  int op_depth;
11157
11680
  svn_wc__db_status_t old_presence;
 
11681
  svn_boolean_t moved_here;
11158
11682
 
11159
11683
    /* If we are adding a file or directory, then we need to get
11160
11684
     repository information from the parent node since "this node" does
11184
11708
 
11185
11709
  /* Figure out the new node's kind. It will be whatever is in WORKING_NODE,
11186
11710
     or there will be a BASE_NODE that has it.  */
 
11711
  old_presence = svn_sqlite__column_token(stmt_info, 3, presence_map);
11187
11712
  new_kind = svn_sqlite__column_token(stmt_info, 4, kind_map);
11188
11713
 
11189
11714
  /* What will the new depth be?  */
11202
11727
                            svn_sqlite__column_text(stmt_info, 2, NULL)) == 0);
11203
11728
    }
11204
11729
 
11205
 
  /* Find the appropriate new properties -- ACTUAL overrides any properties
11206
 
     in WORKING that arrived as part of a copy/move.
11207
 
 
11208
 
     Note: we'll keep them as a big blob of data, rather than
11209
 
     deserialize/serialize them.  */
11210
 
  if (have_act)
11211
 
    prop_blob.data = svn_sqlite__column_blob(stmt_act, 1, &prop_blob.len,
11212
 
                                             scratch_pool);
11213
 
  if (prop_blob.data == NULL)
11214
 
    prop_blob.data = svn_sqlite__column_blob(stmt_info, 14, &prop_blob.len,
11215
 
                                             scratch_pool);
11216
 
 
11217
 
  inherited_prop_blob.data = svn_sqlite__column_blob(stmt_info, 16,
11218
 
                                                     &inherited_prop_blob.len,
11219
 
                                                     scratch_pool);
11220
 
 
11221
 
  if (keep_changelist && have_act)
11222
 
    changelist = svn_sqlite__column_text(stmt_act, 0, scratch_pool);
11223
 
 
11224
 
  old_presence = svn_sqlite__column_token(stmt_info, 3, presence_map);
 
11730
  if (old_presence != svn_wc__db_status_base_deleted)
 
11731
    {
 
11732
      /* Find the appropriate new properties -- ACTUAL overrides any properties
 
11733
         in WORKING that arrived as part of a copy/move.
 
11734
 
 
11735
         Note: we'll keep them as a big blob of data, rather than
 
11736
         deserialize/serialize them.  */
 
11737
      if (have_act)
 
11738
        prop_blob.data = svn_sqlite__column_blob(stmt_act, 1, &prop_blob.len,
 
11739
                                                 scratch_pool);
 
11740
      if (prop_blob.data == NULL)
 
11741
        prop_blob.data = svn_sqlite__column_blob(stmt_info, 14, &prop_blob.len,
 
11742
                                                 scratch_pool);
 
11743
 
 
11744
      inherited_prop_blob.data = svn_sqlite__column_blob(
 
11745
                                            stmt_info, 16,
 
11746
                                            &inherited_prop_blob.len,
 
11747
                                            scratch_pool);
 
11748
 
 
11749
      if (keep_changelist && have_act)
 
11750
        changelist = svn_sqlite__column_text(stmt_act, 0, scratch_pool);
 
11751
 
 
11752
      moved_here = svn_sqlite__column_int(stmt_info, 15);
 
11753
    }
 
11754
  else
 
11755
    {
 
11756
      moved_here = FALSE;
 
11757
      changelist = NULL;
 
11758
    }
11225
11759
 
11226
11760
  /* ### other stuff?  */
11227
11761
 
11232
11766
    {
11233
11767
      int affected_rows;
11234
11768
 
 
11769
      SVN_ERR_ASSERT(op_depth == relpath_depth(local_relpath));
 
11770
 
 
11771
      /* First clear the moves that we are going to delete in a bit */
 
11772
      {
 
11773
        apr_hash_t *old_moves;
 
11774
        apr_hash_index_t *hi;
 
11775
        SVN_ERR(moved_descendant_collect(&old_moves, wcroot, local_relpath, 0,
 
11776
                                         scratch_pool, scratch_pool));
 
11777
 
 
11778
        if (old_moves)
 
11779
          for (hi = apr_hash_first(scratch_pool, old_moves);
 
11780
                hi; hi = apr_hash_next(hi))
 
11781
            {
 
11782
              SVN_ERR(clear_moved_here(wcroot, apr_hash_this_key(hi),
 
11783
                                        scratch_pool));
 
11784
            }
 
11785
      }
 
11786
 
11235
11787
      /* This removes all layers of this node and at the same time determines
11236
11788
         if we need to remove shadowed layers below our descendants. */
11237
11789
 
11264
11816
         be integrated, they really affect a different op-depth and
11265
11817
         completely different nodes (via a different recursion pattern). */
11266
11818
 
11267
 
      /* Collapse descendants of the current op_depth in layer 0 */
11268
 
      SVN_ERR(descendant_commit(wcroot, local_relpath, op_depth,
11269
 
                                repos_id, repos_relpath, new_revision,
11270
 
                                scratch_pool));
11271
 
 
11272
 
      /* And make the recorded local moves represent moves of the node we just
11273
 
         committed. */
11274
 
      SVN_ERR(moved_descendant_commit(wcroot, local_relpath, 0,
 
11819
      if (old_presence != svn_wc__db_status_base_deleted)
 
11820
        {
 
11821
          /* Collapse descendants of the current op_depth to layer 0,
 
11822
             this includes moved-from/to clearing */
 
11823
          SVN_ERR(descendant_commit(wcroot, local_relpath, op_depth,
 
11824
                                    repos_id, repos_relpath, new_revision,
 
11825
                                    scratch_pool));
 
11826
        }
 
11827
 
 
11828
      if (old_presence != svn_wc__db_status_base_deleted)
 
11829
        {
 
11830
          apr_hash_t *moves = NULL;
 
11831
 
 
11832
          SVN_ERR(moved_descendant_collect(&moves, wcroot, local_relpath, 0,
 
11833
                                           scratch_pool, scratch_pool));
 
11834
 
 
11835
          /* And make the recorded local moves represent moves of the node we
 
11836
             just committed. */
 
11837
          SVN_ERR(moved_descendant_commit(wcroot, local_relpath,
11275
11838
                                      repos_id, repos_relpath, new_revision,
11276
 
                                      scratch_pool));
11277
 
 
11278
 
      /* This node is no longer modified, so no node was moved here */
11279
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
11280
 
                                        STMT_CLEAR_MOVED_TO_FROM_DEST));
11281
 
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
11282
 
                                            local_relpath));
11283
 
 
11284
 
      SVN_ERR(svn_sqlite__step_done(stmt));
 
11839
                                      moves, scratch_pool));
 
11840
        }
 
11841
 
 
11842
      if (moved_here)
 
11843
        {
 
11844
          /* This node is no longer modified, so no node was moved here */
 
11845
          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
11846
                                            STMT_CLEAR_MOVED_TO_FROM_DEST));
 
11847
          SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
 
11848
                                                local_relpath));
 
11849
 
 
11850
          SVN_ERR(svn_sqlite__step_done(stmt));
 
11851
        }
11285
11852
    }
11286
 
 
11287
11853
  /* Update or add the BASE_NODE row with all the new information.  */
11288
11854
 
11289
11855
  if (*local_relpath == '\0')
11292
11858
    parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
11293
11859
 
11294
11860
  /* Preserve any incomplete status */
11295
 
  new_presence = (old_presence == svn_wc__db_status_incomplete
11296
 
                  ? svn_wc__db_status_incomplete
11297
 
                  : svn_wc__db_status_normal);
11298
 
 
11299
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
11300
 
                                    STMT_APPLY_CHANGES_TO_BASE_NODE));
11301
 
  /* symlink_target not yet used */
11302
 
  SVN_ERR(svn_sqlite__bindf(stmt, "issisrtstrisnbn",
11303
 
                            wcroot->wc_id, local_relpath,
11304
 
                            parent_relpath,
11305
 
                            repos_id,
11306
 
                            repos_relpath,
11307
 
                            new_revision,
11308
 
                            presence_map, new_presence,
11309
 
                            new_depth_str,
11310
 
                            kind_map, new_kind,
11311
 
                            changed_rev,
11312
 
                            changed_date,
11313
 
                            changed_author,
11314
 
                            prop_blob.data, prop_blob.len));
11315
 
 
11316
 
  SVN_ERR(svn_sqlite__bind_checksum(stmt, 13, new_checksum,
11317
 
                                    scratch_pool));
11318
 
  SVN_ERR(svn_sqlite__bind_properties(stmt, 15, new_dav_cache,
11319
 
                                      scratch_pool));
11320
 
  if (inherited_prop_blob.data != NULL)
11321
 
    {
11322
 
      SVN_ERR(svn_sqlite__bind_blob(stmt, 17, inherited_prop_blob.data,
11323
 
                                    inherited_prop_blob.len));
11324
 
    }
11325
 
 
11326
 
  SVN_ERR(svn_sqlite__step_done(stmt));
 
11861
  if (old_presence != svn_wc__db_status_base_deleted)
 
11862
    {
 
11863
      new_presence = (old_presence == svn_wc__db_status_incomplete
 
11864
                      ? svn_wc__db_status_incomplete
 
11865
                      : svn_wc__db_status_normal);
 
11866
 
 
11867
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
11868
                                        STMT_APPLY_CHANGES_TO_BASE_NODE));
 
11869
      /* symlink_target not yet used */
 
11870
      SVN_ERR(svn_sqlite__bindf(stmt, "issisrtstrisnbn",
 
11871
                                wcroot->wc_id, local_relpath,
 
11872
                                parent_relpath,
 
11873
                                repos_id,
 
11874
                                repos_relpath,
 
11875
                                new_revision,
 
11876
                                presence_map, new_presence,
 
11877
                                new_depth_str,
 
11878
                                kind_map, new_kind,
 
11879
                                changed_rev,
 
11880
                                changed_date,
 
11881
                                changed_author,
 
11882
                                prop_blob.data, prop_blob.len));
 
11883
 
 
11884
      SVN_ERR(svn_sqlite__bind_checksum(stmt, 13, new_checksum,
 
11885
                                        scratch_pool));
 
11886
      SVN_ERR(svn_sqlite__bind_properties(stmt, 15, new_dav_cache,
 
11887
                                          scratch_pool));
 
11888
      if (inherited_prop_blob.data != NULL)
 
11889
        {
 
11890
          SVN_ERR(svn_sqlite__bind_blob(stmt, 17, inherited_prop_blob.data,
 
11891
                                        inherited_prop_blob.len));
 
11892
        }
 
11893
 
 
11894
      SVN_ERR(svn_sqlite__step_done(stmt));
 
11895
    }
 
11896
  else
 
11897
    {
 
11898
      struct insert_base_baton_t ibb;
 
11899
      blank_ibb(&ibb);
 
11900
 
 
11901
      ibb.repos_id = repos_id;
 
11902
      ibb.status = svn_wc__db_status_not_present;
 
11903
      ibb.kind = new_kind;
 
11904
      ibb.repos_relpath = repos_relpath;
 
11905
      ibb.revision = new_revision;
 
11906
 
 
11907
      SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
 
11908
 
 
11909
      keep_changelist = FALSE; /* Nothing there */
 
11910
    }
11327
11911
 
11328
11912
  if (have_act)
11329
11913
    {
11351
11935
        }
11352
11936
    }
11353
11937
 
11354
 
  if (new_kind == svn_node_dir)
11355
 
    {
11356
 
      /* When committing a directory, we should have its new children.  */
11357
 
      /* ### one day. just not today.  */
11358
 
#if 0
11359
 
      SVN_ERR_ASSERT(new_children != NULL);
11360
 
#endif
11361
 
 
11362
 
      /* ### process the children  */
11363
 
    }
11364
 
 
11365
11938
  if (!no_unlock)
11366
11939
    {
11367
11940
      svn_sqlite__stmt_t *lock_stmt;
 
11941
      svn_boolean_t op_root = (op_depth > 0
 
11942
                               && (relpath_depth(local_relpath) == op_depth));
11368
11943
 
 
11944
      /* If we are committing an add of a delete, we can assume we own
 
11945
         all locks at or below REPOS_RELPATH (or the server would have
 
11946
         denied the commit). As we must have passed these to the server
 
11947
         we can now safely remove them.
 
11948
       */
11369
11949
      SVN_ERR(svn_sqlite__get_statement(&lock_stmt, wcroot->sdb,
11370
 
                                        STMT_DELETE_LOCK_RECURSIVELY));
 
11950
                                        op_root
 
11951
                                          ? STMT_DELETE_LOCK_RECURSIVELY
 
11952
                                          : STMT_DELETE_LOCK));
11371
11953
      SVN_ERR(svn_sqlite__bindf(lock_stmt, "is", repos_id, repos_relpath));
11372
11954
      SVN_ERR(svn_sqlite__step_done(lock_stmt));
11373
11955
    }
11387
11969
                         apr_time_t changed_date,
11388
11970
                         const char *changed_author,
11389
11971
                         const svn_checksum_t *new_checksum,
11390
 
                         const apr_array_header_t *new_children,
11391
11972
                         apr_hash_t *new_dav_cache,
11392
11973
                         svn_boolean_t keep_changelist,
11393
11974
                         svn_boolean_t no_unlock,
11399
11980
 
11400
11981
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
11401
11982
  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_revision));
11402
 
  SVN_ERR_ASSERT(new_checksum == NULL || new_children == NULL);
11403
11983
 
11404
11984
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
11405
11985
                              local_abspath, scratch_pool, scratch_pool));
11408
11988
  SVN_WC__DB_WITH_TXN(
11409
11989
    commit_node(wcroot, local_relpath,
11410
11990
                new_revision, changed_revision, changed_date, changed_author,
11411
 
                new_checksum, new_children, new_dav_cache, keep_changelist,
 
11991
                new_checksum, new_dav_cache, keep_changelist,
11412
11992
                no_unlock, work_items, scratch_pool),
11413
11993
    wcroot);
11414
11994
 
11543
12123
 * non-NULL update the entry to the new url specified by NEW_REPOS_RELPATH,
11544
12124
 * NEW_REPOS_ID.  If NEW_REV is valid, make this the node's working revision.
11545
12125
 *
 
12126
 * NODE_STATUS, NODE_KIND, NODE_REVISION and NODE_REPOS_RELPATH represent the
 
12127
 * values as stored currently in WCROOT for LOCAL_RELPATH.
 
12128
 *
11546
12129
 * If WCROOT_IPROPS is not NULL it is a hash mapping const char * absolute
11547
12130
 * working copy paths to depth-first ordered arrays of
11548
12131
 * svn_prop_inherited_item_t * structures.  If the absolute path equivalent
11555
12138
static svn_error_t *
11556
12139
bump_node_revision(svn_wc__db_wcroot_t *wcroot,
11557
12140
                   const char *local_relpath,
 
12141
                   svn_wc__db_status_t node_status,
 
12142
                   svn_node_kind_t node_kind,
 
12143
                   svn_revnum_t node_revision,
 
12144
                   const char *node_repos_relpath,
11558
12145
                   apr_int64_t new_repos_id,
11559
12146
                   const char *new_repos_relpath,
11560
12147
                   svn_revnum_t new_rev,
11567
12154
                   apr_pool_t *scratch_pool)
11568
12155
{
11569
12156
  apr_pool_t *iterpool;
11570
 
  const apr_array_header_t *children;
11571
 
  int i;
11572
 
  svn_wc__db_status_t status;
11573
 
  svn_node_kind_t db_kind;
11574
 
  svn_revnum_t revision;
11575
 
  const char *repos_relpath;
11576
 
  apr_int64_t repos_id;
 
12157
  apr_hash_t *children;
 
12158
  apr_hash_index_t *hi;
11577
12159
  svn_boolean_t set_repos_relpath = FALSE;
11578
 
  svn_boolean_t update_root;
11579
12160
  svn_depth_t depth_below_here = depth;
11580
12161
  apr_array_header_t *iprops = NULL;
11581
12162
 
11582
 
  /* Skip an excluded path and its descendants. */
11583
 
  if (svn_hash_gets(exclude_relpaths, local_relpath))
11584
 
    return SVN_NO_ERROR;
11585
 
 
11586
 
  SVN_ERR(svn_wc__db_base_get_info_internal(&status, &db_kind, &revision,
11587
 
                                            &repos_relpath, &repos_id,
11588
 
                                            NULL, NULL, NULL, NULL, NULL,
11589
 
                                            NULL, NULL, NULL, NULL, &update_root,
11590
 
                                            wcroot, local_relpath,
11591
 
                                            scratch_pool, scratch_pool));
11592
 
 
11593
 
  /* Skip file externals */
11594
 
  if (update_root
11595
 
      && db_kind == svn_node_file
11596
 
      && !is_root)
11597
 
    return SVN_NO_ERROR;
11598
 
 
11599
 
  if (skip_when_dir && db_kind == svn_node_dir)
11600
 
    return SVN_NO_ERROR;
11601
 
 
11602
 
  /* If the node is still marked 'not-present', then the server did not
11603
 
     re-add it.  So it's really gone in this revision, thus we remove the node.
11604
 
 
11605
 
     If the node is still marked 'server-excluded' and yet is not the same
11606
 
     revision as new_rev, then the server did not re-add it, nor
11607
 
     re-server-exclude it, so we can remove the node. */
11608
 
  if (!is_root
11609
 
      && (status == svn_wc__db_status_not_present
11610
 
          || (status == svn_wc__db_status_server_excluded &&
11611
 
              revision != new_rev)))
11612
 
    {
11613
 
      return svn_error_trace(db_base_remove(wcroot, local_relpath,
11614
 
                                            db, FALSE, FALSE, FALSE,
11615
 
                                            SVN_INVALID_REVNUM,
11616
 
                                            NULL, NULL, scratch_pool));
11617
 
    }
11618
 
 
11619
 
  if (new_repos_relpath != NULL && strcmp(repos_relpath, new_repos_relpath))
 
12163
  if (new_repos_relpath != NULL
 
12164
      && strcmp(node_repos_relpath, new_repos_relpath))
11620
12165
    set_repos_relpath = TRUE;
11621
12166
 
11622
12167
  if (wcroot_iprops)
11626
12171
 
11627
12172
  if (iprops
11628
12173
      || set_repos_relpath
11629
 
      || (SVN_IS_VALID_REVNUM(new_rev) && new_rev != revision))
 
12174
      || (SVN_IS_VALID_REVNUM(new_rev) && new_rev != node_revision))
11630
12175
    {
11631
12176
      SVN_ERR(db_op_set_rev_repos_relpath_iprops(wcroot, local_relpath,
11632
12177
                                                 iprops, new_rev,
11638
12183
 
11639
12184
  /* Early out */
11640
12185
  if (depth <= svn_depth_empty
11641
 
      || db_kind != svn_node_dir
11642
 
      || status == svn_wc__db_status_server_excluded
11643
 
      || status == svn_wc__db_status_excluded
11644
 
      || status == svn_wc__db_status_not_present)
 
12186
      || node_kind != svn_node_dir
 
12187
      || node_status == svn_wc__db_status_server_excluded
 
12188
      || node_status == svn_wc__db_status_excluded
 
12189
      || node_status == svn_wc__db_status_not_present)
11645
12190
    return SVN_NO_ERROR;
11646
12191
 
11647
12192
  /* And now recurse over the children */
11653
12198
 
11654
12199
  iterpool = svn_pool_create(scratch_pool);
11655
12200
 
11656
 
  SVN_ERR(gather_repo_children(&children, wcroot, local_relpath, 0,
11657
 
                               scratch_pool, iterpool));
11658
 
  for (i = 0; i < children->nelts; i++)
 
12201
  SVN_ERR(base_get_children_info(&children, wcroot, local_relpath, 0,
 
12202
                                 scratch_pool, iterpool));
 
12203
  for (hi = apr_hash_first(scratch_pool, children); hi; hi = apr_hash_next(hi))
11659
12204
    {
11660
 
      const char *child_basename = APR_ARRAY_IDX(children, i, const char *);
 
12205
      const char *child_basename = apr_hash_this_key(hi);
 
12206
      const struct svn_wc__db_base_info_t *child_info;
11661
12207
      const char *child_local_relpath;
11662
12208
      const char *child_repos_relpath = NULL;
11663
12209
 
11664
12210
      svn_pool_clear(iterpool);
11665
12211
 
 
12212
      child_info = apr_hash_this_val(hi);
 
12213
 
 
12214
      if (child_info->update_root && child_info->kind == svn_node_file)
 
12215
        continue; /* Skip file externals */
 
12216
 
 
12217
      if (depth < svn_depth_immediates && child_info->kind == svn_node_dir)
 
12218
          continue; /* Skip directories */
 
12219
 
 
12220
      child_local_relpath = svn_relpath_join(local_relpath, child_basename,
 
12221
                                             iterpool);
 
12222
 
 
12223
      /* Don't touch nodes that can't be touched via the exclude list */
 
12224
      if (svn_hash_gets(exclude_relpaths, child_local_relpath))
 
12225
          continue;
 
12226
 
 
12227
      /* If the node is still marked 'not-present', then the server did not
 
12228
          re-add it.  So it's really gone in this revision, thus we remove the
 
12229
          node.
 
12230
 
 
12231
          If the node is still marked 'server-excluded' and yet is not the same
 
12232
          revision as new_rev, then the server did not re-add it, nor
 
12233
          re-server-exclude it, so we can remove the node. */
 
12234
      if (child_info->status == svn_wc__db_status_not_present
 
12235
          || (child_info->status == svn_wc__db_status_server_excluded &&
 
12236
              child_info->revnum != new_rev))
 
12237
        {
 
12238
          svn_sqlite__stmt_t *stmt;
 
12239
          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
12240
                                    STMT_DELETE_BASE_NODE));
 
12241
          SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, child_local_relpath));
 
12242
          SVN_ERR(svn_sqlite__step_done(stmt));
 
12243
          continue;
 
12244
        }
 
12245
 
11666
12246
      /* Derive the new URL for the current (child) entry */
11667
12247
      if (new_repos_relpath)
11668
12248
        child_repos_relpath = svn_relpath_join(new_repos_relpath,
11669
12249
                                               child_basename, iterpool);
11670
12250
 
11671
 
      child_local_relpath = svn_relpath_join(local_relpath, child_basename,
11672
 
                                             iterpool);
11673
 
 
11674
 
      SVN_ERR(bump_node_revision(wcroot, child_local_relpath, new_repos_id,
 
12251
      SVN_ERR(bump_node_revision(wcroot, child_local_relpath,
 
12252
                                 child_info->status,
 
12253
                                 child_info->kind,
 
12254
                                 child_info->revnum,
 
12255
                                 child_info->repos_relpath,
 
12256
                                 new_repos_id,
11675
12257
                                 child_repos_relpath, new_rev,
11676
12258
                                 depth_below_here,
11677
12259
                                 exclude_relpaths, wcroot_iprops,
11699
12281
                           svn_revnum_t new_revision,
11700
12282
                           apr_hash_t *exclude_relpaths,
11701
12283
                           apr_hash_t *wcroot_iprops,
 
12284
                           svn_boolean_t empty_update,
11702
12285
                           svn_wc_notify_func2_t notify_func,
11703
12286
                           void *notify_baton,
11704
12287
                           apr_pool_t *scratch_pool)
11707
12290
  svn_node_kind_t kind;
11708
12291
  svn_error_t *err;
11709
12292
  apr_int64_t new_repos_id = INVALID_REPOS_ID;
 
12293
  svn_revnum_t revision;
 
12294
  const char *repos_relpath;
11710
12295
 
11711
 
  err = svn_wc__db_base_get_info_internal(&status, &kind, NULL, NULL, NULL,
 
12296
  err = svn_wc__db_base_get_info_internal(&status, &kind, &revision,
 
12297
                                          &repos_relpath, NULL,
11712
12298
                                          NULL, NULL, NULL, NULL, NULL, NULL,
11713
12299
                                          NULL, NULL, NULL, NULL,
11714
12300
                                          wcroot, local_relpath,
11738
12324
                            new_repos_uuid,
11739
12325
                            wcroot->sdb, scratch_pool));
11740
12326
 
11741
 
  SVN_ERR(bump_node_revision(wcroot, local_relpath, new_repos_id,
 
12327
  SVN_ERR(bump_node_revision(wcroot, local_relpath,
 
12328
                             status, kind,  revision, repos_relpath,
 
12329
                             new_repos_id,
11742
12330
                             new_repos_relpath, new_revision,
11743
12331
                             depth, exclude_relpaths,
11744
12332
                             wcroot_iprops,
11745
12333
                             TRUE /* is_root */, FALSE, db,
11746
12334
                             scratch_pool));
11747
12335
 
 
12336
  /* ### TODO: Use empty_update flag for change knowledge */
11748
12337
  SVN_ERR(svn_wc__db_bump_moved_away(wcroot, local_relpath, depth, db,
11749
12338
                                     scratch_pool));
11750
12339
 
11765
12354
                                         svn_revnum_t new_revision,
11766
12355
                                         apr_hash_t *exclude_relpaths,
11767
12356
                                         apr_hash_t *wcroot_iprops,
 
12357
                                         svn_boolean_t empty_update,
11768
12358
                                         svn_wc_notify_func2_t notify_func,
11769
12359
                                         void *notify_baton,
11770
12360
                                         apr_pool_t *scratch_pool)
11787
12377
    bump_revisions_post_update(wcroot, local_relpath, db,
11788
12378
                               depth, new_repos_relpath, new_repos_root_url,
11789
12379
                               new_repos_uuid, new_revision,
11790
 
                               exclude_relpaths, wcroot_iprops,
 
12380
                               exclude_relpaths, wcroot_iprops, empty_update,
11791
12381
                               notify_func, notify_baton, scratch_pool),
11792
12382
    wcroot);
11793
12383
 
11864
12454
static svn_error_t *
11865
12455
lock_remove_txn(svn_wc__db_wcroot_t *wcroot,
11866
12456
                const char *local_relpath,
 
12457
                svn_skel_t *work_items,
11867
12458
                apr_pool_t *scratch_pool)
11868
12459
{
11869
12460
  const char *repos_relpath;
11883
12474
 
11884
12475
  SVN_ERR(svn_sqlite__step_done(stmt));
11885
12476
 
 
12477
  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
 
12478
 
11886
12479
  return SVN_NO_ERROR;
11887
12480
}
11888
12481
 
11890
12483
svn_error_t *
11891
12484
svn_wc__db_lock_remove(svn_wc__db_t *db,
11892
12485
                       const char *local_abspath,
 
12486
                       svn_skel_t *work_items,
11893
12487
                       apr_pool_t *scratch_pool)
11894
12488
{
11895
12489
  svn_wc__db_wcroot_t *wcroot;
11902
12496
  VERIFY_USABLE_WCROOT(wcroot);
11903
12497
 
11904
12498
  SVN_WC__DB_WITH_TXN(
11905
 
    lock_remove_txn(wcroot, local_relpath, scratch_pool),
 
12499
    lock_remove_txn(wcroot, local_relpath, work_items, scratch_pool),
11906
12500
    wcroot);
11907
12501
 
11908
12502
  /* There may be some entries, and the lock info is now out of date.  */
11911
12505
  return SVN_NO_ERROR;
11912
12506
}
11913
12507
 
11914
 
 
11915
 
svn_error_t *
11916
 
svn_wc__db_scan_base_repos(const char **repos_relpath,
11917
 
                           const char **repos_root_url,
11918
 
                           const char **repos_uuid,
11919
 
                           svn_wc__db_t *db,
11920
 
                           const char *local_abspath,
11921
 
                           apr_pool_t *result_pool,
11922
 
                           apr_pool_t *scratch_pool)
11923
 
{
11924
 
  svn_wc__db_wcroot_t *wcroot;
11925
 
  const char *local_relpath;
11926
 
  apr_int64_t repos_id;
11927
 
 
11928
 
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
11929
 
 
11930
 
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
11931
 
                              local_abspath, scratch_pool, scratch_pool));
11932
 
  VERIFY_USABLE_WCROOT(wcroot);
11933
 
 
11934
 
  SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
11935
 
                                            repos_relpath, &repos_id,
11936
 
                                            NULL, NULL, NULL, NULL, NULL,
11937
 
                                            NULL, NULL, NULL, NULL, NULL,
11938
 
                                            wcroot, local_relpath,
11939
 
                                            result_pool, scratch_pool));
11940
 
  SVN_ERR(svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid, wcroot->sdb,
11941
 
                                      repos_id, result_pool));
11942
 
 
11943
 
  return SVN_NO_ERROR;
11944
 
}
11945
 
 
11946
 
 
11947
12508
/* A helper for scan_addition().
11948
12509
 * Compute moved-from information for the node at LOCAL_RELPATH which
11949
12510
 * has been determined as having been moved-here.
12042
12603
  return SVN_NO_ERROR;
12043
12604
}
12044
12605
 
12045
 
/* The body of scan_addition().
12046
 
 */
 
12606
/* Like svn_wc__db_scan_addition(), but with WCROOT+LOCAL_RELPATH instead of
 
12607
   DB+LOCAL_ABSPATH.
 
12608
 
 
12609
   The output value of *ORIGINAL_REPOS_ID will be INVALID_REPOS_ID if there
 
12610
   is no 'copy-from' repository.  */
12047
12611
static svn_error_t *
12048
 
scan_addition_txn(svn_wc__db_status_t *status,
12049
 
                  const char **op_root_relpath_p,
12050
 
                  const char **repos_relpath,
12051
 
                  apr_int64_t *repos_id,
12052
 
                  const char **original_repos_relpath,
12053
 
                  apr_int64_t *original_repos_id,
12054
 
                  svn_revnum_t *original_revision,
12055
 
                  const char **moved_from_relpath,
12056
 
                  const char **moved_from_op_root_relpath,
12057
 
                  int *moved_from_op_depth,
12058
 
                  svn_wc__db_wcroot_t *wcroot,
12059
 
                  const char *local_relpath,
12060
 
                  apr_pool_t *result_pool,
12061
 
                  apr_pool_t *scratch_pool)
 
12612
scan_addition(svn_wc__db_status_t *status,
 
12613
              const char **op_root_relpath_p,
 
12614
              const char **repos_relpath,
 
12615
              apr_int64_t *repos_id,
 
12616
              const char **original_repos_relpath,
 
12617
              apr_int64_t *original_repos_id,
 
12618
              svn_revnum_t *original_revision,
 
12619
              const char **moved_from_relpath,
 
12620
              const char **moved_from_op_root_relpath,
 
12621
              int *moved_from_op_depth,
 
12622
              svn_wc__db_wcroot_t *wcroot,
 
12623
              const char *local_relpath,
 
12624
              apr_pool_t *result_pool,
 
12625
              apr_pool_t *scratch_pool)
12062
12626
{
12063
12627
  const char *op_root_relpath;
12064
12628
  const char *build_relpath = "";
12087
12651
    svn_boolean_t have_row;
12088
12652
    svn_wc__db_status_t presence;
12089
12653
    int op_depth;
12090
 
    const char *repos_prefix_path = "";
12091
 
    int i;
 
12654
    const char *repos_prefix_path;
12092
12655
 
12093
12656
    /* ### is it faster to fetch fewer columns? */
12094
12657
    SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
12137
12700
 
12138
12701
 
12139
12702
    /* Calculate the op root local path components */
12140
 
    op_root_relpath = local_relpath;
12141
 
 
12142
 
    for (i = relpath_depth(local_relpath); i > op_depth; --i)
12143
 
      {
12144
 
        /* Calculate the path of the operation root */
12145
 
        repos_prefix_path =
12146
 
          svn_relpath_join(svn_relpath_basename(op_root_relpath, NULL),
12147
 
                           repos_prefix_path,
12148
 
                           scratch_pool);
12149
 
        op_root_relpath = svn_relpath_dirname(op_root_relpath, scratch_pool);
12150
 
      }
 
12703
    op_root_relpath = svn_relpath_prefix(local_relpath, op_depth,
 
12704
                                         scratch_pool);
 
12705
    repos_prefix_path = svn_relpath_skip_ancestor(op_root_relpath,
 
12706
                                                  local_relpath);
12151
12707
 
12152
12708
    if (op_root_relpath_p)
12153
12709
      *op_root_relpath_p = apr_pstrdup(result_pool, op_root_relpath);
12239
12795
      {
12240
12796
        const char *base_relpath;
12241
12797
 
12242
 
    while (TRUE)
12243
 
      {
12244
 
 
12245
 
        SVN_ERR(svn_sqlite__reset(stmt));
12246
 
 
12247
 
        /* Pointing at op_depth, look at the parent */
12248
 
        repos_prefix_path =
12249
 
          svn_relpath_join(svn_relpath_basename(op_root_relpath, NULL),
12250
 
                           repos_prefix_path,
12251
 
                           scratch_pool);
12252
 
        op_root_relpath = svn_relpath_dirname(op_root_relpath, scratch_pool);
12253
 
 
12254
 
 
12255
 
        SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, op_root_relpath));
12256
 
        SVN_ERR(svn_sqlite__step(&have_row, stmt));
12257
 
 
12258
 
        if (! have_row)
12259
 
          break;
12260
 
 
12261
 
        op_depth = svn_sqlite__column_int(stmt, 0);
12262
 
 
12263
 
        /* Skip to op_depth */
12264
 
        for (i = relpath_depth(op_root_relpath); i > op_depth; i--)
 
12798
        while (TRUE)
12265
12799
          {
12266
 
            /* Calculate the path of the operation root */
 
12800
            const char *tmp;
 
12801
 
 
12802
            SVN_ERR(svn_sqlite__reset(stmt));
 
12803
 
 
12804
            /* Pointing at op_depth, look at the parent */
12267
12805
            repos_prefix_path =
12268
 
              svn_relpath_join(svn_relpath_basename(op_root_relpath, NULL),
12269
 
                               repos_prefix_path,
12270
 
                               scratch_pool);
12271
 
            op_root_relpath =
12272
 
              svn_relpath_dirname(op_root_relpath, scratch_pool);
 
12806
                svn_relpath_join(svn_relpath_basename(op_root_relpath, NULL),
 
12807
                                 repos_prefix_path,
 
12808
                                 scratch_pool);
 
12809
            op_root_relpath = svn_relpath_dirname(op_root_relpath, scratch_pool);
 
12810
 
 
12811
 
 
12812
            SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, op_root_relpath));
 
12813
            SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
12814
 
 
12815
            if (! have_row)
 
12816
              break;
 
12817
 
 
12818
            op_depth = svn_sqlite__column_int(stmt, 0);
 
12819
 
 
12820
            /* Skip to op_depth */
 
12821
            tmp = op_root_relpath;
 
12822
 
 
12823
            op_root_relpath = svn_relpath_prefix(op_root_relpath, op_depth,
 
12824
                                                 scratch_pool);
 
12825
            repos_prefix_path = svn_relpath_join(
 
12826
                                                 svn_relpath_skip_ancestor(op_root_relpath, tmp),
 
12827
                                                 repos_prefix_path, scratch_pool);
12273
12828
          }
12274
 
      }
12275
12829
 
12276
12830
      SVN_ERR(svn_sqlite__reset(stmt));
12277
12831
 
12331
12885
  return SVN_NO_ERROR;
12332
12886
}
12333
12887
 
12334
 
 
12335
 
/* Like svn_wc__db_scan_addition(), but with WCROOT+LOCAL_RELPATH instead of
12336
 
   DB+LOCAL_ABSPATH.
12337
 
 
12338
 
   The output value of *ORIGINAL_REPOS_ID will be INVALID_REPOS_ID if there
12339
 
   is no 'copy-from' repository.  */
12340
 
static svn_error_t *
12341
 
scan_addition(svn_wc__db_status_t *status,
12342
 
              const char **op_root_relpath,
 
12888
svn_error_t *
 
12889
svn_wc__db_scan_addition_internal(
 
12890
              svn_wc__db_status_t *status,
 
12891
              const char **op_root_relpath_p,
12343
12892
              const char **repos_relpath,
12344
12893
              apr_int64_t *repos_id,
12345
12894
              const char **original_repos_relpath,
12346
12895
              apr_int64_t *original_repos_id,
12347
12896
              svn_revnum_t *original_revision,
12348
 
              const char **moved_from_relpath,
12349
 
              const char **moved_from_op_root_relpath,
12350
 
              int *moved_from_op_depth,
12351
12897
              svn_wc__db_wcroot_t *wcroot,
12352
12898
              const char *local_relpath,
12353
12899
              apr_pool_t *result_pool,
12354
12900
              apr_pool_t *scratch_pool)
12355
12901
{
12356
 
  SVN_WC__DB_WITH_TXN(
12357
 
    scan_addition_txn(status, op_root_relpath, repos_relpath, repos_id,
12358
 
                      original_repos_relpath, original_repos_id,
12359
 
                      original_revision, moved_from_relpath,
12360
 
                      moved_from_op_root_relpath, moved_from_op_depth,
12361
 
                      wcroot, local_relpath, result_pool, scratch_pool),
12362
 
    wcroot);
12363
 
  return SVN_NO_ERROR;
 
12902
  return svn_error_trace(
 
12903
      scan_addition(status, op_root_relpath_p, repos_relpath, repos_id,
 
12904
                    original_repos_relpath, original_repos_id,
 
12905
                    original_revision, NULL, NULL, NULL,
 
12906
                    wcroot, local_relpath, result_pool, scratch_pool));
12364
12907
}
12365
12908
 
12366
 
 
12367
12909
svn_error_t *
12368
12910
svn_wc__db_scan_addition(svn_wc__db_status_t *status,
12369
12911
                         const char **op_root_abspath,
12395
12937
                              local_abspath, scratch_pool, scratch_pool));
12396
12938
  VERIFY_USABLE_WCROOT(wcroot);
12397
12939
 
12398
 
  SVN_ERR(scan_addition(status,
 
12940
  SVN_WC__DB_WITH_TXN4(
 
12941
          scan_addition(status,
12399
12942
                        op_root_abspath
12400
12943
                                ? &op_root_relpath
12401
12944
                                : NULL,
12403
12946
                        original_repos_relpath, original_repos_id_p,
12404
12947
                        original_revision,
12405
12948
                        NULL, NULL, NULL,
12406
 
                        wcroot, local_relpath, result_pool, scratch_pool));
 
12949
                        wcroot, local_relpath, result_pool, scratch_pool),
 
12950
          svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid, wcroot,
 
12951
                                      repos_id, result_pool),
 
12952
          svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
 
12953
                                      wcroot, original_repos_id,
 
12954
                                      result_pool),
 
12955
          SVN_NO_ERROR,
 
12956
          wcroot);
12407
12957
 
12408
12958
  if (op_root_abspath)
12409
12959
    *op_root_abspath = svn_dirent_join(wcroot->abspath, op_root_relpath,
12411
12961
  /* REPOS_ID must be valid if requested; ORIGINAL_REPOS_ID need not be. */
12412
12962
  SVN_ERR_ASSERT(repos_id_p == NULL || repos_id != INVALID_REPOS_ID);
12413
12963
 
12414
 
  SVN_ERR(svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid, wcroot->sdb,
12415
 
                                      repos_id, result_pool));
12416
 
  SVN_ERR(svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
12417
 
                                      wcroot->sdb, original_repos_id,
12418
 
                                      result_pool));
12419
 
 
12420
12964
  return SVN_NO_ERROR;
12421
12965
}
12422
12966
 
12444
12988
                              local_abspath, scratch_pool, scratch_pool));
12445
12989
  VERIFY_USABLE_WCROOT(wcroot);
12446
12990
 
12447
 
  SVN_ERR(scan_addition(&status,
 
12991
  SVN_WC__DB_WITH_TXN(
 
12992
          scan_addition(&status,
12448
12993
                        op_root_abspath
12449
12994
                                ? &op_root_relpath
12450
12995
                                : NULL,
12460
13005
                        moved_from_delete_abspath
12461
13006
                            ? &moved_from_op_depth
12462
13007
                            : NULL,
12463
 
                        wcroot, local_relpath, scratch_pool, scratch_pool));
 
13008
                        wcroot, local_relpath, scratch_pool, scratch_pool),
 
13009
          wcroot);
12464
13010
 
12465
13011
  if (status != svn_wc__db_status_moved_here || !moved_from_relpath)
12466
13012
    return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
12484
13030
  /* The deleted node is either where we moved from, or one of its ancestors */
12485
13031
  if (moved_from_delete_abspath)
12486
13032
    {
12487
 
      const char *tmp = moved_from_op_root_relpath;
12488
 
 
12489
 
      SVN_ERR_ASSERT(moved_from_op_depth >= 0);
12490
 
 
12491
 
      while (relpath_depth(tmp) > moved_from_op_depth)
12492
 
        tmp = svn_relpath_dirname(tmp, scratch_pool);
 
13033
      const char *tmp = svn_relpath_prefix(moved_from_op_root_relpath,
 
13034
                                           moved_from_op_depth, scratch_pool);
12493
13035
 
12494
13036
      *moved_from_delete_abspath = svn_dirent_join(wcroot->abspath, tmp,
12495
13037
                                                   scratch_pool);
12498
13040
  return SVN_NO_ERROR;
12499
13041
}
12500
13042
 
12501
 
/* ###
 
13043
/* ### Recursive helper for svn_wc__db_follow_moved_to()
12502
13044
 */
12503
13045
static svn_error_t *
12504
 
follow_moved_to(apr_array_header_t **moved_tos,
 
13046
follow_moved_to(svn_wc__db_wcroot_t *wcroot,
 
13047
                const char *local_relpath,
12505
13048
                int op_depth,
12506
 
                const char *repos_path,
12507
 
                svn_revnum_t revision,
12508
 
                svn_wc__db_wcroot_t *wcroot,
12509
 
                const char *local_relpath,
 
13049
                apr_array_header_t **moved_tos,
12510
13050
                apr_pool_t *result_pool,
12511
13051
                apr_pool_t *scratch_pool)
12512
13052
{
12513
13053
  svn_sqlite__stmt_t *stmt;
12514
13054
  svn_boolean_t have_row;
12515
 
  int working_op_depth;
12516
 
  const char *ancestor_relpath, *node_moved_to = NULL;
 
13055
  int shadowing_op_depth;
 
13056
  const char *ancestor_relpath;
 
13057
  const char *node_moved_to = NULL;
12517
13058
  int i;
12518
13059
 
12519
 
  SVN_ERR_ASSERT((!op_depth && !repos_path) || (op_depth && repos_path));
12520
 
 
 
13060
  /* Obtain the depth of the node directly shadowing local_relpath
 
13061
     as it exists at OP_DEPTH, and perhaps moved to info */
12521
13062
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
12522
13063
                                    STMT_SELECT_OP_DEPTH_MOVED_TO));
12523
13064
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
12525
13066
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
12526
13067
  if (have_row)
12527
13068
    {
12528
 
      working_op_depth = svn_sqlite__column_int(stmt, 0);
 
13069
      shadowing_op_depth = svn_sqlite__column_int(stmt, 0);
12529
13070
      node_moved_to = svn_sqlite__column_text(stmt, 1, result_pool);
12530
 
      if (!repos_path)
 
13071
 
 
13072
      if (node_moved_to)
12531
13073
        {
12532
 
          SVN_ERR(svn_sqlite__step(&have_row, stmt));
12533
 
          if (!have_row || svn_sqlite__column_revnum(stmt, 0))
12534
 
            return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
12535
 
                                     svn_sqlite__reset(stmt),
12536
 
                                     _("The base node '%s' was not found."),
12537
 
                                     path_for_error_message(wcroot,
12538
 
                                                            local_relpath,
12539
 
                                                            scratch_pool));
12540
 
          repos_path = svn_sqlite__column_text(stmt, 2, scratch_pool);
12541
 
          revision = svn_sqlite__column_revnum(stmt, 3);
 
13074
          struct svn_wc__db_moved_to_t *moved_to;
 
13075
 
 
13076
          moved_to = apr_palloc(result_pool, sizeof(*moved_to));
 
13077
          moved_to->op_depth = shadowing_op_depth;
 
13078
          moved_to->local_relpath = node_moved_to;
 
13079
          APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to;
12542
13080
        }
12543
13081
    }
 
13082
 
12544
13083
  SVN_ERR(svn_sqlite__reset(stmt));
12545
13084
 
12546
 
  if (node_moved_to)
12547
 
    {
12548
 
      svn_boolean_t have_row2;
12549
 
 
12550
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
12551
 
                                        STMT_SELECT_MOVED_HERE));
12552
 
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, node_moved_to,
12553
 
                                relpath_depth(node_moved_to)));
12554
 
      SVN_ERR(svn_sqlite__step(&have_row2, stmt));
12555
 
      if (!have_row2 || !svn_sqlite__column_int(stmt, 0)
12556
 
          || revision != svn_sqlite__column_revnum(stmt, 3)
12557
 
          || strcmp(repos_path, svn_sqlite__column_text(stmt, 2, NULL)))
12558
 
        node_moved_to = NULL;
12559
 
      SVN_ERR(svn_sqlite__reset(stmt));
12560
 
    }
12561
 
 
12562
 
  if (node_moved_to)
12563
 
    {
12564
 
      struct svn_wc__db_moved_to_t *moved_to;
12565
 
 
12566
 
      moved_to = apr_palloc(result_pool, sizeof(*moved_to));
12567
 
      moved_to->op_depth = working_op_depth;
12568
 
      moved_to->local_relpath = node_moved_to;
12569
 
      APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to;
12570
 
    }
12571
 
 
12572
 
  /* A working row with moved_to, or no working row, and we are done. */
12573
 
  if (node_moved_to || !have_row)
12574
 
    return SVN_NO_ERROR;
12575
 
 
 
13085
  if (!have_row)
 
13086
    {
 
13087
      /* Node is not shadowed, so not moved */
 
13088
      return SVN_NO_ERROR;
 
13089
    }
 
13090
  else if (node_moved_to)
 
13091
    {
 
13092
      /* Moved directly, so we have the final location */
 
13093
      return SVN_NO_ERROR;
 
13094
    }
12576
13095
  /* Need to handle being moved via an ancestor. */
12577
13096
  ancestor_relpath = local_relpath;
12578
 
  for (i = relpath_depth(local_relpath); i > working_op_depth; --i)
 
13097
  for (i = relpath_depth(local_relpath); i > shadowing_op_depth; --i)
12579
13098
    {
12580
13099
      const char *ancestor_moved_to;
12581
13100
 
12584
13103
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
12585
13104
                                        STMT_SELECT_MOVED_TO));
12586
13105
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, ancestor_relpath,
12587
 
                                working_op_depth));
12588
 
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
12589
 
      SVN_ERR_ASSERT(have_row);
 
13106
                                shadowing_op_depth));
 
13107
      SVN_ERR(svn_sqlite__step_row(stmt));
 
13108
 
12590
13109
      ancestor_moved_to = svn_sqlite__column_text(stmt, 0, scratch_pool);
12591
13110
      SVN_ERR(svn_sqlite__reset(stmt));
12592
13111
      if (ancestor_moved_to)
12593
13112
        {
 
13113
          struct svn_wc__db_moved_to_t *moved_to;
 
13114
 
12594
13115
          node_moved_to
12595
 
            = svn_relpath_join(ancestor_moved_to,
12596
 
                               svn_relpath_skip_ancestor(ancestor_relpath,
12597
 
                                                         local_relpath),
12598
 
                               result_pool);
12599
 
 
12600
 
          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
12601
 
                                            STMT_SELECT_MOVED_HERE));
12602
 
          SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, node_moved_to,
12603
 
                                    relpath_depth(ancestor_moved_to)));
12604
 
          SVN_ERR(svn_sqlite__step(&have_row, stmt));
12605
 
          if (!have_row)
12606
 
            ancestor_moved_to = NULL;
12607
 
          else if (!svn_sqlite__column_int(stmt, 0))
12608
 
            {
12609
 
              svn_wc__db_status_t presence
12610
 
                = svn_sqlite__column_token(stmt, 1, presence_map);
12611
 
              if (presence != svn_wc__db_status_not_present)
12612
 
                ancestor_moved_to = NULL;
12613
 
              else
12614
 
                {
12615
 
                  SVN_ERR(svn_sqlite__step(&have_row, stmt));
12616
 
                  if (!have_row && !svn_sqlite__column_int(stmt, 0))
12617
 
                    ancestor_moved_to = NULL;
12618
 
                }
12619
 
            }
12620
 
          SVN_ERR(svn_sqlite__reset(stmt));
12621
 
          if (!ancestor_moved_to)
12622
 
            break;
12623
 
          /* verify repos_path points back? */
12624
 
        }
12625
 
      if (ancestor_moved_to)
12626
 
        {
12627
 
          struct svn_wc__db_moved_to_t *moved_to;
 
13116
              = svn_relpath_join(ancestor_moved_to,
 
13117
                                 svn_relpath_skip_ancestor(ancestor_relpath,
 
13118
                                                           local_relpath),
 
13119
                                 result_pool);
12628
13120
 
12629
13121
          moved_to = apr_palloc(result_pool, sizeof(*moved_to));
12630
 
          moved_to->op_depth = working_op_depth;
 
13122
          moved_to->op_depth = shadowing_op_depth;
12631
13123
          moved_to->local_relpath = node_moved_to;
12632
13124
          APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to;
12633
13125
 
12634
 
          SVN_ERR(follow_moved_to(moved_tos, relpath_depth(ancestor_moved_to),
12635
 
                                  repos_path, revision, wcroot, node_moved_to,
12636
 
                                  result_pool, scratch_pool));
 
13126
          SVN_ERR(follow_moved_to(wcroot, node_moved_to,
 
13127
                                  relpath_depth(ancestor_moved_to),
 
13128
                                  moved_tos, result_pool, scratch_pool));
 
13129
 
12637
13130
          break;
12638
13131
        }
12639
13132
    }
12661
13154
                              sizeof(struct svn_wc__db_moved_to_t *));
12662
13155
 
12663
13156
  /* ### Wrap in a transaction */
12664
 
  SVN_ERR(follow_moved_to(moved_tos, 0, NULL, SVN_INVALID_REVNUM,
12665
 
                          wcroot, local_relpath,
12666
 
                          result_pool, scratch_pool));
 
13157
  SVN_WC__DB_WITH_TXN(follow_moved_to(wcroot, local_relpath, 0, moved_tos,
 
13158
                                      result_pool, scratch_pool),
 
13159
                      wcroot);
12667
13160
 
12668
13161
  /* ### Convert moved_to to abspath */
12669
13162
 
12670
13163
  return SVN_NO_ERROR;
12671
13164
}
12672
13165
 
12673
 
/* Extract the moved-to information for LOCAL_RELPATH at OP-DEPTH by
12674
 
   examining the lowest working node above OP_DEPTH.  The output paths
12675
 
   are NULL if there is no move, otherwise:
12676
 
 
12677
 
   *MOVE_DST_RELPATH: the moved-to destination of LOCAL_RELPATH.
12678
 
 
12679
 
   *MOVE_DST_OP_ROOT_RELPATH: the moved-to destination of the root of
12680
 
   the move of LOCAL_RELPATH. This may be equal to *MOVE_DST_RELPATH
12681
 
   if LOCAL_RELPATH is the root of the move.
12682
 
 
12683
 
   *MOVE_SRC_ROOT_RELPATH: the root of the move source.  For moves
12684
 
   inside a delete this will be different from *MOVE_SRC_OP_ROOT_RELPATH.
12685
 
 
12686
 
   *MOVE_SRC_OP_ROOT_RELPATH: the root of the source layer that
12687
 
   contains the move.  For moves inside deletes this is the root of
12688
 
   the delete, for other moves this is the root of the move.
12689
 
 
12690
 
   Given a path A/B/C with A/B moved to X then for A/B/C
12691
 
 
12692
 
     MOVE_DST_RELPATH is X/C
12693
 
     MOVE_DST_OP_ROOT_RELPATH is X
12694
 
     MOVE_SRC_ROOT_RELPATH is A/B
12695
 
     MOVE_SRC_OP_ROOT_RELPATH is A/B
12696
 
 
12697
 
   If A is then deleted the MOVE_DST_RELPATH, MOVE_DST_OP_ROOT_RELPATH
12698
 
   and MOVE_SRC_ROOT_RELPATH remain the same but MOVE_SRC_OP_ROOT_RELPATH
12699
 
   changes to A.
12700
 
 
12701
 
   ### Think about combining with scan_deletion?  Also with
12702
 
   ### scan_addition to get moved-to for replaces?  Do we need to
12703
 
   ### return the op-root of the move source, i.e. A/B in the example
12704
 
   ### above?  */
12705
13166
svn_error_t *
12706
 
svn_wc__db_op_depth_moved_to(const char **move_dst_relpath,
12707
 
                             const char **move_dst_op_root_relpath,
12708
 
                             const char **move_src_root_relpath,
12709
 
                             const char **move_src_op_root_relpath,
12710
 
                             int op_depth,
12711
 
                             svn_wc__db_wcroot_t *wcroot,
12712
 
                             const char *local_relpath,
12713
 
                             apr_pool_t *result_pool,
12714
 
                             apr_pool_t *scratch_pool)
 
13167
svn_wc__db_scan_moved_to_internal(const char **move_src_relpath,
 
13168
                                  const char **move_dst_relpath,
 
13169
                                  const char **delete_relpath,
 
13170
                                  svn_wc__db_wcroot_t *wcroot,
 
13171
                                  const char *local_relpath,
 
13172
                                  int op_depth,
 
13173
                                  apr_pool_t *result_pool,
 
13174
                                  apr_pool_t *scratch_pool)
12715
13175
{
12716
13176
  svn_sqlite__stmt_t *stmt;
12717
13177
  svn_boolean_t have_row;
12718
13178
  int delete_op_depth;
12719
13179
  const char *relpath = local_relpath;
12720
 
 
12721
 
  *move_dst_relpath = *move_dst_op_root_relpath = NULL;
12722
 
  *move_src_root_relpath = *move_src_op_root_relpath = NULL;
12723
 
 
12724
 
  do
12725
 
    {
 
13180
  const char *dst_relpath;
 
13181
 
 
13182
  SVN_ERR_ASSERT(local_relpath[0]); /* Not valid on the WC root */
 
13183
 
 
13184
  if (move_src_relpath)
 
13185
    *move_src_relpath = NULL;
 
13186
  if (move_dst_relpath)
 
13187
    *move_dst_relpath = NULL;
 
13188
  if (delete_relpath)
 
13189
    *delete_relpath = NULL;
 
13190
 
 
13191
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
13192
                                    STMT_SELECT_OP_DEPTH_MOVED_TO));
 
13193
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, relpath, op_depth));
 
13194
 
 
13195
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
13196
 
 
13197
  if (!have_row)
 
13198
    {
 
13199
      return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
 
13200
                               svn_sqlite__reset(stmt),
 
13201
                               _("Node '%s' is not shadowed"),
 
13202
                               path_for_error_message(wcroot, local_relpath,
 
13203
                                                      scratch_pool));
 
13204
    }
 
13205
 
 
13206
  delete_op_depth = svn_sqlite__column_int(stmt, 0);
 
13207
  dst_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool);
 
13208
 
 
13209
  SVN_ERR(svn_sqlite__reset(stmt));
 
13210
 
 
13211
  while (!dst_relpath && have_row)
 
13212
    {
 
13213
      relpath = svn_relpath_dirname(relpath, scratch_pool);
 
13214
 
 
13215
      if (relpath_depth(relpath) < delete_op_depth)
 
13216
        break;
 
13217
 
12726
13218
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
12727
 
                                        STMT_SELECT_LOWEST_WORKING_NODE));
12728
 
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, relpath, op_depth));
 
13219
                                        STMT_SELECT_DEPTH_NODE));
 
13220
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, relpath,
 
13221
                                delete_op_depth));
 
13222
 
12729
13223
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
13224
 
12730
13225
      if (have_row)
12731
 
        {
12732
 
          delete_op_depth = svn_sqlite__column_int(stmt, 0);
12733
 
          *move_dst_op_root_relpath = svn_sqlite__column_text(stmt, 3,
12734
 
                                                              result_pool);
12735
 
          if (*move_dst_op_root_relpath)
12736
 
            *move_src_root_relpath = apr_pstrdup(result_pool, relpath);
12737
 
        }
 
13226
        dst_relpath = svn_sqlite__column_text(stmt, 13, scratch_pool);
 
13227
 
12738
13228
      SVN_ERR(svn_sqlite__reset(stmt));
12739
 
      if (!*move_dst_op_root_relpath)
12740
 
        relpath = svn_relpath_dirname(relpath, scratch_pool);
12741
13229
    }
12742
 
  while (!*move_dst_op_root_relpath
12743
 
        && have_row && delete_op_depth <= relpath_depth(relpath));
12744
13230
 
12745
 
  if (*move_dst_op_root_relpath)
 
13231
  if (dst_relpath)
12746
13232
    {
12747
 
      *move_dst_relpath
12748
 
        = svn_relpath_join(*move_dst_op_root_relpath,
12749
 
                           svn_relpath_skip_ancestor(relpath, local_relpath),
12750
 
                           result_pool);
12751
 
      while (delete_op_depth < relpath_depth(relpath))
12752
 
        relpath = svn_relpath_dirname(relpath, scratch_pool);
12753
 
      *move_src_op_root_relpath = apr_pstrdup(result_pool, relpath);
 
13233
      if (move_src_relpath)
 
13234
        *move_src_relpath = apr_pstrdup(result_pool, relpath);
 
13235
 
 
13236
      if (move_dst_relpath)
 
13237
        *move_dst_relpath = apr_pstrdup(result_pool, dst_relpath);
 
13238
 
 
13239
      if (delete_relpath)
 
13240
        *delete_relpath = svn_relpath_prefix(local_relpath, delete_op_depth,
 
13241
                                             result_pool);
12754
13242
    }
12755
13243
 
12756
13244
  return SVN_NO_ERROR;
12763
13251
svn_wc__db_base_moved_to(const char **move_dst_abspath,
12764
13252
                         const char **move_dst_op_root_abspath,
12765
13253
                         const char **move_src_root_abspath,
12766
 
                         const char **move_src_op_root_abspath,
 
13254
                         const char **delete_abspath,
12767
13255
                         svn_wc__db_t *db,
12768
13256
                         const char *local_abspath,
12769
13257
                         apr_pool_t *result_pool,
12771
13259
{
12772
13260
  svn_wc__db_wcroot_t *wcroot;
12773
13261
  const char *local_relpath;
12774
 
  const char *move_dst_relpath, *move_dst_op_root_relpath;
12775
 
  const char *move_src_root_relpath, *move_src_op_root_relpath;
 
13262
  const char *dst_root_relpath;
 
13263
  const char *src_root_relpath, *delete_relpath;
12776
13264
 
12777
13265
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
12778
13266
 
 
13267
 
12779
13268
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
12780
13269
                              local_abspath, scratch_pool, scratch_pool));
12781
13270
  VERIFY_USABLE_WCROOT(wcroot);
12782
13271
 
12783
 
  SVN_WC__DB_WITH_TXN(svn_wc__db_op_depth_moved_to(&move_dst_relpath,
12784
 
                                                   &move_dst_op_root_relpath,
12785
 
                                                   &move_src_root_relpath,
12786
 
                                                   &move_src_op_root_relpath,
12787
 
                                                   0 /* BASE op-depth */,
12788
 
                                                   wcroot, local_relpath,
12789
 
                                                   scratch_pool, scratch_pool),
 
13272
  SVN_WC__DB_WITH_TXN(svn_wc__db_scan_moved_to_internal(&src_root_relpath,
 
13273
                                                        &dst_root_relpath,
 
13274
                                                        &delete_relpath,
 
13275
                                                        wcroot, local_relpath,
 
13276
                                                        0 /* BASE */,
 
13277
                                                        scratch_pool,
 
13278
                                                        scratch_pool),
12790
13279
                      wcroot);
12791
13280
 
12792
13281
  if (move_dst_abspath)
12793
 
    *move_dst_abspath
12794
 
      = move_dst_relpath
12795
 
      ? svn_dirent_join(wcroot->abspath, move_dst_relpath, result_pool)
12796
 
      : NULL;
 
13282
    *move_dst_abspath =
 
13283
        dst_root_relpath
 
13284
          ? svn_dirent_join(wcroot->abspath,
 
13285
                            svn_dirent_join(
 
13286
                                    dst_root_relpath,
 
13287
                                    svn_relpath_skip_ancestor(src_root_relpath,
 
13288
                                                              local_relpath),
 
13289
                                    scratch_pool),
 
13290
                            result_pool)
 
13291
          : NULL;
12797
13292
 
12798
13293
  if (move_dst_op_root_abspath)
12799
 
    *move_dst_op_root_abspath
12800
 
      = move_dst_op_root_relpath
12801
 
      ? svn_dirent_join(wcroot->abspath, move_dst_op_root_relpath, result_pool)
12802
 
      : NULL;
 
13294
    *move_dst_op_root_abspath =
 
13295
          dst_root_relpath
 
13296
              ? svn_dirent_join(wcroot->abspath, dst_root_relpath, result_pool)
 
13297
              : NULL;
12803
13298
 
12804
13299
  if (move_src_root_abspath)
12805
 
    *move_src_root_abspath
12806
 
      = move_src_root_relpath
12807
 
      ? svn_dirent_join(wcroot->abspath, move_src_root_relpath, result_pool)
12808
 
      : NULL;
 
13300
    *move_src_root_abspath =
 
13301
          src_root_relpath
 
13302
              ? svn_dirent_join(wcroot->abspath, src_root_relpath, result_pool)
 
13303
              : NULL;
12809
13304
 
12810
 
  if (move_src_op_root_abspath)
12811
 
    *move_src_op_root_abspath
12812
 
      = move_src_op_root_relpath
12813
 
      ? svn_dirent_join(wcroot->abspath, move_src_op_root_relpath, result_pool)
12814
 
      : NULL;
 
13305
  if (delete_abspath)
 
13306
    *delete_abspath =
 
13307
          delete_relpath
 
13308
              ? svn_dirent_join(wcroot->abspath, delete_relpath, result_pool)
 
13309
              : NULL;
12815
13310
 
12816
13311
  return SVN_NO_ERROR;
12817
13312
}
12834
13329
                    SDB_FILE,
12835
13330
                    NULL, SVN_INVALID_REVNUM, svn_depth_unknown,
12836
13331
                    TRUE /* exclusive */,
 
13332
                    0 /* timeout */,
12837
13333
                    wc_db->state_pool, scratch_pool));
12838
13334
 
12839
13335
  SVN_ERR(svn_wc__db_pdh_create_wcroot(&wcroot,
12841
13337
                                                   dir_abspath),
12842
13338
                                       *sdb, *wc_id, FORMAT_FROM_SDB,
12843
13339
                                       FALSE /* auto-upgrade */,
12844
 
                                       FALSE /* enforce_empty_wq */,
12845
13340
                                       wc_db->state_pool, scratch_pool));
12846
13341
 
12847
13342
  /* The WCROOT is complete. Stash it into DB.  */
12850
13345
  return SVN_NO_ERROR;
12851
13346
}
12852
13347
 
12853
 
 
12854
 
svn_error_t *
12855
 
svn_wc__db_upgrade_apply_dav_cache(svn_sqlite__db_t *sdb,
12856
 
                                   const char *dir_relpath,
12857
 
                                   apr_hash_t *cache_values,
12858
 
                                   apr_pool_t *scratch_pool)
12859
 
{
12860
 
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
12861
 
  apr_int64_t wc_id;
12862
 
  apr_hash_index_t *hi;
12863
 
  svn_sqlite__stmt_t *stmt;
12864
 
 
12865
 
  SVN_ERR(svn_wc__db_util_fetch_wc_id(&wc_id, sdb, iterpool));
12866
 
 
12867
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
12868
 
                                    STMT_UPDATE_BASE_NODE_DAV_CACHE));
12869
 
 
12870
 
  /* Iterate over all the wcprops, writing each one to the wc_db. */
12871
 
  for (hi = apr_hash_first(scratch_pool, cache_values);
12872
 
       hi;
12873
 
       hi = apr_hash_next(hi))
12874
 
    {
12875
 
      const char *name = svn__apr_hash_index_key(hi);
12876
 
      apr_hash_t *props = svn__apr_hash_index_val(hi);
12877
 
      const char *local_relpath;
12878
 
 
12879
 
      svn_pool_clear(iterpool);
12880
 
 
12881
 
      local_relpath = svn_relpath_join(dir_relpath, name, iterpool);
12882
 
 
12883
 
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
12884
 
      SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, iterpool));
12885
 
      SVN_ERR(svn_sqlite__step_done(stmt));
12886
 
    }
12887
 
 
12888
 
  svn_pool_destroy(iterpool);
12889
 
 
12890
 
  return SVN_NO_ERROR;
12891
 
}
12892
 
 
12893
 
 
12894
 
svn_error_t *
12895
 
svn_wc__db_upgrade_apply_props(svn_sqlite__db_t *sdb,
12896
 
                               const char *dir_abspath,
12897
 
                               const char *local_relpath,
12898
 
                               apr_hash_t *base_props,
12899
 
                               apr_hash_t *revert_props,
12900
 
                               apr_hash_t *working_props,
12901
 
                               int original_format,
12902
 
                               apr_int64_t wc_id,
12903
 
                               apr_pool_t *scratch_pool)
12904
 
{
12905
 
  svn_sqlite__stmt_t *stmt;
12906
 
  svn_boolean_t have_row;
12907
 
  int top_op_depth = -1;
12908
 
  int below_op_depth = -1;
12909
 
  svn_wc__db_status_t top_presence;
12910
 
  svn_wc__db_status_t below_presence;
12911
 
  int affected_rows;
12912
 
 
12913
 
  /* ### working_props: use set_props_txn.
12914
 
     ### if working_props == NULL, then skip. what if they equal the
12915
 
     ### pristine props? we should probably do the compare here.
12916
 
     ###
12917
 
     ### base props go into WORKING_NODE if avail, otherwise BASE.
12918
 
     ###
12919
 
     ### revert only goes into BASE. (and WORKING better be there!)
12920
 
 
12921
 
     Prior to 1.4.0 (ORIGINAL_FORMAT < 8), REVERT_PROPS did not exist. If a
12922
 
     file was deleted, then a copy (potentially with props) was disallowed
12923
 
     and could not replace the deletion. An addition *could* be performed,
12924
 
     but that would never bring its own props.
12925
 
 
12926
 
     1.4.0 through 1.4.5 created the concept of REVERT_PROPS, but had a
12927
 
     bug in svn_wc_add_repos_file2() whereby a copy-with-props did NOT
12928
 
     construct a REVERT_PROPS if the target had no props. Thus, reverting
12929
 
     the delete/copy would see no REVERT_PROPS to restore, leaving the
12930
 
     props from the copy source intact, and appearing as if they are (now)
12931
 
     the base props for the previously-deleted file. (wc corruption)
12932
 
 
12933
 
     1.4.6 ensured that an empty REVERT_PROPS would be established at all
12934
 
     times. See issue 2530, and r861670 as starting points.
12935
 
 
12936
 
     We will use ORIGINAL_FORMAT and SVN_WC__NO_REVERT_FILES to determine
12937
 
     the handling of our inputs, relative to the state of this node.
12938
 
  */
12939
 
 
12940
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_NODE_INFO));
12941
 
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
12942
 
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
12943
 
  if (have_row)
12944
 
    {
12945
 
      top_op_depth = svn_sqlite__column_int(stmt, 0);
12946
 
      top_presence = svn_sqlite__column_token(stmt, 3, presence_map);
12947
 
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
12948
 
      if (have_row)
12949
 
        {
12950
 
          below_op_depth = svn_sqlite__column_int(stmt, 0);
12951
 
          below_presence = svn_sqlite__column_token(stmt, 3, presence_map);
12952
 
        }
12953
 
    }
12954
 
  SVN_ERR(svn_sqlite__reset(stmt));
12955
 
 
12956
 
  /* Detect the buggy scenario described above. We cannot upgrade this
12957
 
     working copy if we have no idea where BASE_PROPS should go.  */
12958
 
  if (original_format > SVN_WC__NO_REVERT_FILES
12959
 
      && revert_props == NULL
12960
 
      && top_op_depth != -1
12961
 
      && top_presence == svn_wc__db_status_normal
12962
 
      && below_op_depth != -1
12963
 
      && below_presence != svn_wc__db_status_not_present)
12964
 
    {
12965
 
      /* There should be REVERT_PROPS, so it appears that we just ran into
12966
 
         the described bug. Sigh.  */
12967
 
      return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
12968
 
                               _("The properties of '%s' are in an "
12969
 
                                 "indeterminate state and cannot be "
12970
 
                                 "upgraded. See issue #2530."),
12971
 
                               svn_dirent_local_style(
12972
 
                                 svn_dirent_join(dir_abspath, local_relpath,
12973
 
                                                 scratch_pool), scratch_pool));
12974
 
    }
12975
 
 
12976
 
  /* Need at least one row, or two rows if there are revert props */
12977
 
  if (top_op_depth == -1
12978
 
      || (below_op_depth == -1 && revert_props))
12979
 
    return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
12980
 
                             _("Insufficient NODES rows for '%s'"),
12981
 
                             svn_dirent_local_style(
12982
 
                               svn_dirent_join(dir_abspath, local_relpath,
12983
 
                                               scratch_pool), scratch_pool));
12984
 
 
12985
 
  /* one row, base props only: upper row gets base props
12986
 
     two rows, base props only: lower row gets base props
12987
 
     two rows, revert props only: lower row gets revert props
12988
 
     two rows, base and revert props: upper row gets base, lower gets revert */
12989
 
 
12990
 
 
12991
 
  if (revert_props || below_op_depth == -1)
12992
 
    {
12993
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
12994
 
                                        STMT_UPDATE_NODE_PROPS));
12995
 
      SVN_ERR(svn_sqlite__bindf(stmt, "isd",
12996
 
                                wc_id, local_relpath, top_op_depth));
12997
 
      SVN_ERR(svn_sqlite__bind_properties(stmt, 4, base_props, scratch_pool));
12998
 
      SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
12999
 
 
13000
 
      SVN_ERR_ASSERT(affected_rows == 1);
13001
 
    }
13002
 
 
13003
 
  if (below_op_depth != -1)
13004
 
    {
13005
 
      apr_hash_t *props = revert_props ? revert_props : base_props;
13006
 
 
13007
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
13008
 
                                        STMT_UPDATE_NODE_PROPS));
13009
 
      SVN_ERR(svn_sqlite__bindf(stmt, "isd",
13010
 
                                wc_id, local_relpath, below_op_depth));
13011
 
      SVN_ERR(svn_sqlite__bind_properties(stmt, 4, props, scratch_pool));
13012
 
      SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
13013
 
 
13014
 
      SVN_ERR_ASSERT(affected_rows == 1);
13015
 
    }
13016
 
 
13017
 
  /* If there are WORKING_PROPS, then they always go into ACTUAL_NODE.  */
13018
 
  if (working_props != NULL
13019
 
      && base_props != NULL)
13020
 
    {
13021
 
      apr_array_header_t *diffs;
13022
 
 
13023
 
      SVN_ERR(svn_prop_diffs(&diffs, working_props, base_props, scratch_pool));
13024
 
 
13025
 
      if (diffs->nelts == 0)
13026
 
        working_props = NULL; /* No differences */
13027
 
    }
13028
 
 
13029
 
  if (working_props != NULL)
13030
 
    {
13031
 
      SVN_ERR(set_actual_props(wc_id, local_relpath, working_props,
13032
 
                               sdb, scratch_pool));
13033
 
    }
13034
 
 
13035
 
  return SVN_NO_ERROR;
13036
 
}
13037
 
 
13038
13348
svn_error_t *
13039
13349
svn_wc__db_upgrade_insert_external(svn_wc__db_t *db,
13040
13350
                                   const char *local_abspath,
13110
13420
}
13111
13421
 
13112
13422
svn_error_t *
13113
 
svn_wc__db_upgrade_get_repos_id(apr_int64_t *repos_id,
13114
 
                                svn_sqlite__db_t *sdb,
13115
 
                                const char *repos_root_url,
13116
 
                                apr_pool_t *scratch_pool)
 
13423
svn_wc__db_wq_add_internal(svn_wc__db_wcroot_t *wcroot,
 
13424
                           const svn_skel_t *work_item,
 
13425
                           apr_pool_t *scratch_pool)
13117
13426
{
13118
 
  svn_sqlite__stmt_t *stmt;
13119
 
  svn_boolean_t have_row;
13120
 
 
13121
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_REPOSITORY));
13122
 
  SVN_ERR(svn_sqlite__bindf(stmt, "s", repos_root_url));
13123
 
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
13124
 
 
13125
 
  if (!have_row)
13126
 
    return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt),
13127
 
                             _("Repository '%s' not found in the database"),
13128
 
                             repos_root_url);
13129
 
 
13130
 
  *repos_id = svn_sqlite__column_int64(stmt, 0);
13131
 
  return svn_error_trace(svn_sqlite__reset(stmt));
 
13427
  /* Add the work item(s) to the WORK_QUEUE.  */
 
13428
  return svn_error_trace(add_work_items(wcroot->sdb, work_item,
 
13429
                                        scratch_pool));
13132
13430
}
13133
13431
 
13134
 
 
13135
13432
svn_error_t *
13136
13433
svn_wc__db_wq_add(svn_wc__db_t *db,
13137
13434
                  const char *wri_abspath,
13244
13541
  for (hi = apr_hash_first(scratch_pool, record_map); hi;
13245
13542
       hi = apr_hash_next(hi))
13246
13543
    {
13247
 
      const char *local_abspath = svn__apr_hash_index_key(hi);
13248
 
      const svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi);
 
13544
      const char *local_abspath = apr_hash_this_key(hi);
 
13545
      const svn_io_dirent2_t *dirent = apr_hash_this_val(hi);
13249
13546
      const char *local_relpath = svn_dirent_skip_ancestor(wcroot->abspath,
13250
13547
                                                           local_abspath);
13251
13548
 
13458
13755
       hi;
13459
13756
       hi = apr_hash_next(hi))
13460
13757
    {
13461
 
      const svn_wc__db_wcroot_t *wcroot = svn__apr_hash_index_val(hi);
 
13758
      const svn_wc__db_wcroot_t *wcroot = apr_hash_this_val(hi);
13462
13759
 
13463
13760
      /* This is highly redundant, 'cause the same WCROOT will appear many
13464
13761
         times in dir_data. */
13645
13942
 
13646
13943
svn_error_t *
13647
13944
svn_wc__db_read_conflict(svn_skel_t **conflict,
 
13945
                         svn_node_kind_t *kind,
 
13946
                         apr_hash_t **props,
13648
13947
                         svn_wc__db_t *db,
13649
13948
                         const char *local_abspath,
13650
13949
                         apr_pool_t *result_pool,
13658
13957
                              local_abspath, scratch_pool, scratch_pool));
13659
13958
  VERIFY_USABLE_WCROOT(wcroot);
13660
13959
 
13661
 
  return svn_error_trace(svn_wc__db_read_conflict_internal(conflict, wcroot,
13662
 
                                                           local_relpath,
 
13960
  return svn_error_trace(svn_wc__db_read_conflict_internal(conflict, kind, props,
 
13961
                                                           wcroot, local_relpath,
13663
13962
                                                           result_pool,
13664
13963
                                                           scratch_pool));
13665
13964
}
13666
13965
 
13667
13966
svn_error_t *
13668
13967
svn_wc__db_read_conflict_internal(svn_skel_t **conflict,
 
13968
                                  svn_node_kind_t *kind,
 
13969
                                  apr_hash_t **props,
13669
13970
                                  svn_wc__db_wcroot_t *wcroot,
13670
13971
                                  const char *local_relpath,
13671
13972
                                  apr_pool_t *result_pool,
13674
13975
  svn_sqlite__stmt_t *stmt;
13675
13976
  svn_boolean_t have_row;
13676
13977
 
 
13978
  if (kind)
 
13979
    *kind = svn_node_none;
 
13980
  if (props)
 
13981
    *props = NULL;
 
13982
 
13677
13983
  /* Check if we have a conflict in ACTUAL */
13678
13984
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
13679
13985
                                    STMT_SELECT_ACTUAL_NODE));
13681
13987
 
13682
13988
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
13683
13989
 
13684
 
  if (! have_row)
 
13990
  if (have_row)
13685
13991
    {
13686
 
      /* Do this while stmt is still open to avoid closing the sqlite
13687
 
         transaction and then reopening. */
13688
 
      svn_sqlite__stmt_t *stmt_node;
13689
 
      svn_error_t *err;
13690
 
 
13691
 
      err = svn_sqlite__get_statement(&stmt_node, wcroot->sdb,
13692
 
                                      STMT_SELECT_NODE_INFO);
13693
 
 
13694
 
      if (err)
13695
 
        stmt_node = NULL;
 
13992
      apr_size_t cfl_len;
 
13993
      const void *cfl_data;
 
13994
 
 
13995
      /* svn_skel__parse doesn't copy data, so store in result_pool */
 
13996
      cfl_data = svn_sqlite__column_blob(stmt, 2, &cfl_len, result_pool);
 
13997
 
 
13998
      if (cfl_data)
 
13999
        *conflict = svn_skel__parse(cfl_data, cfl_len, result_pool);
13696
14000
      else
13697
 
        err = svn_sqlite__bindf(stmt_node, "is", wcroot->wc_id,
13698
 
                                local_relpath);
13699
 
 
13700
 
      if (!err)
13701
 
        err = svn_sqlite__step(&have_row, stmt_node);
13702
 
 
13703
 
      if (stmt_node)
13704
 
        err = svn_error_compose_create(err,
13705
 
                                       svn_sqlite__reset(stmt_node));
 
14001
        *conflict = NULL;
 
14002
 
 
14003
      if (props)
 
14004
        {
 
14005
          svn_error_t *err;
 
14006
 
 
14007
          err = svn_error_trace(svn_sqlite__column_properties(props, stmt, 1,
 
14008
                                                              result_pool,
 
14009
                                                              scratch_pool));
 
14010
 
 
14011
          if (err)
 
14012
            return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 
14013
        }
 
14014
    }
 
14015
  else
 
14016
    *conflict = NULL;
 
14017
 
 
14018
  SVN_ERR(svn_sqlite__reset(stmt));
 
14019
 
 
14020
  if (!have_row || kind || (props && !*props))
 
14021
    {
 
14022
      svn_error_t *err = NULL;
 
14023
      svn_boolean_t have_info = FALSE;
 
14024
 
 
14025
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
14026
                                        STMT_SELECT_NODE_INFO));
 
14027
 
 
14028
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
 
14029
                                local_relpath));
 
14030
 
 
14031
      SVN_ERR(svn_sqlite__step(&have_info, stmt));
 
14032
 
 
14033
      if (have_info)
 
14034
        {
 
14035
          if (kind)
 
14036
            {
 
14037
              svn_wc__db_status_t status;
 
14038
              int op_depth = svn_sqlite__column_int(stmt, 0);
 
14039
 
 
14040
              status = svn_sqlite__column_token(stmt, 3, presence_map);
 
14041
 
 
14042
              if (op_depth > 0)
 
14043
                err = convert_to_working_status(&status, status);
 
14044
 
 
14045
              if (!err && (status == svn_wc__db_status_normal
 
14046
                           || status == svn_wc__db_status_added
 
14047
                           || status == svn_wc__db_status_deleted
 
14048
                           || status == svn_wc__db_status_incomplete))
 
14049
                {
 
14050
                  *kind = svn_sqlite__column_token(stmt, 4, kind_map);
 
14051
                }
 
14052
            }
 
14053
 
 
14054
          /* Need props, and no props in ACTUAL? */
 
14055
          if (!err && (props && !*props))
 
14056
            {
 
14057
              err = svn_sqlite__column_properties(props, stmt, 14,
 
14058
                                                  result_pool, scratch_pool);
 
14059
            }
 
14060
        }
13706
14061
 
13707
14062
      SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
13708
14063
 
13709
 
      if (have_row)
 
14064
      if (!have_row && !have_info)
13710
14065
        {
13711
 
          *conflict = NULL;
13712
 
          return SVN_NO_ERROR;
13713
 
        }
13714
 
 
13715
 
      return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
13716
 
                               _("The node '%s' was not found."),
 
14066
          return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
 
14067
                                   _("The node '%s' was not found."),
13717
14068
                                   path_for_error_message(wcroot,
13718
14069
                                                          local_relpath,
13719
14070
                                                          scratch_pool));
 
14071
        }
13720
14072
    }
13721
14073
 
13722
 
  {
13723
 
    apr_size_t cfl_len;
13724
 
    const void *cfl_data;
13725
 
 
13726
 
    /* svn_skel__parse doesn't copy data, so store in result_pool */
13727
 
    cfl_data = svn_sqlite__column_blob(stmt, 2, &cfl_len, result_pool);
13728
 
 
13729
 
    if (cfl_data)
13730
 
      *conflict = svn_skel__parse(cfl_data, cfl_len, result_pool);
13731
 
    else
13732
 
      *conflict = NULL;
13733
 
 
13734
 
    return svn_error_trace(svn_sqlite__reset(stmt));
13735
 
  }
 
14074
  return SVN_NO_ERROR;
13736
14075
}
13737
14076
 
13738
14077
 
13749
14088
  const char *local_relpath;
13750
14089
  svn_sqlite__stmt_t *stmt_info;
13751
14090
  svn_boolean_t have_info;
 
14091
  svn_wc__db_status_t status;
13752
14092
 
13753
14093
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
13754
14094
 
13780
14120
        }
13781
14121
    }
13782
14122
 
 
14123
  status = svn_sqlite__column_token(stmt_info, 3, presence_map);
 
14124
 
 
14125
  if (show_deleted && status == svn_wc__db_status_base_deleted)
 
14126
    {
 
14127
      /* Let's return the kind of what is really deleted insead of what
 
14128
         we have cached in the base-deleted record */
 
14129
 
 
14130
      SVN_ERR(svn_sqlite__step(&have_info, stmt_info));
 
14131
 
 
14132
      if (!have_info)
 
14133
        {
 
14134
          /* No lower layer deleted? Database inconsistency! */
 
14135
          *kind = svn_node_none;
 
14136
          return svn_error_trace(svn_sqlite__reset(stmt_info));
 
14137
        }
 
14138
    }
 
14139
 
13783
14140
  if (!(show_deleted && show_hidden))
13784
14141
    {
13785
14142
      int op_depth = svn_sqlite__column_int(stmt_info, 0);
13786
14143
      svn_boolean_t report_none = FALSE;
13787
 
      svn_wc__db_status_t status = svn_sqlite__column_token(stmt_info, 3,
13788
 
                                                            presence_map);
13789
14144
 
13790
14145
      if (op_depth > 0)
13791
14146
        SVN_ERR(convert_to_working_status(&status, status));
13821
14176
  return svn_error_trace(svn_sqlite__reset(stmt_info));
13822
14177
}
13823
14178
 
13824
 
 
13825
 
svn_error_t *
13826
 
svn_wc__db_node_hidden(svn_boolean_t *hidden,
13827
 
                       svn_wc__db_t *db,
13828
 
                       const char *local_abspath,
13829
 
                       apr_pool_t *scratch_pool)
13830
 
{
13831
 
  svn_wc__db_wcroot_t *wcroot;
13832
 
  const char *local_relpath;
13833
 
  svn_wc__db_status_t status;
13834
 
 
13835
 
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
13836
 
 
13837
 
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
13838
 
                              local_abspath, scratch_pool, scratch_pool));
13839
 
  VERIFY_USABLE_WCROOT(wcroot);
13840
 
 
13841
 
  SVN_ERR(read_info(&status, NULL, NULL, NULL, NULL, NULL,
13842
 
                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
13843
 
                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
13844
 
                    NULL, NULL, NULL,
13845
 
                    wcroot, local_relpath,
13846
 
                    scratch_pool, scratch_pool));
13847
 
 
13848
 
  *hidden = (status == svn_wc__db_status_server_excluded
13849
 
             || status == svn_wc__db_status_not_present
13850
 
             || status == svn_wc__db_status_excluded);
13851
 
 
13852
 
  return SVN_NO_ERROR;
13853
 
}
13854
 
 
13855
 
 
13856
14179
svn_error_t *
13857
14180
svn_wc__db_is_wcroot(svn_boolean_t *is_wcroot,
13858
14181
                     svn_wc__db_t *db,
14017
14340
                                           wcroot->abspath,
14018
14341
                                           svn_wc_get_adm_dir(scratch_pool),
14019
14342
                                           WCROOT_TEMPDIR_RELPATH,
14020
 
                                           NULL);
 
14343
                                           SVN_VA_NULL);
14021
14344
  return SVN_NO_ERROR;
14022
14345
}
14023
14346
 
14046
14369
                 const char *local_relpath,
14047
14370
                 int levels_to_lock,
14048
14371
                 svn_boolean_t steal_lock,
 
14372
                 svn_boolean_t enforce_empty_wq,
14049
14373
                 apr_pool_t *scratch_pool)
14050
14374
{
14051
14375
  svn_sqlite__stmt_t *stmt;
14075
14399
                                                        scratch_pool));
14076
14400
    }
14077
14401
 
 
14402
  if (enforce_empty_wq)
 
14403
    SVN_ERR(svn_wc__db_verify_no_work(wcroot->sdb));
 
14404
 
14078
14405
  /* Check if there are nodes locked below the new lock root */
14079
14406
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_FIND_WC_LOCK));
14080
14407
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
14101
14428
 
14102
14429
      /* Check if we are the lock owner, because we should be able to
14103
14430
         extend our lock. */
14104
 
      err = wclock_owns_lock(&own_lock, wcroot, lock_relpath,
14105
 
                             TRUE, scratch_pool);
 
14431
      err = svn_wc__db_wclock_owns_lock_internal(&own_lock, wcroot,
 
14432
                                                 lock_relpath,
 
14433
                                                 TRUE, scratch_pool);
14106
14434
 
14107
14435
      if (err)
14108
14436
        SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
14190
14518
  err = svn_sqlite__insert(NULL, stmt);
14191
14519
  if (err)
14192
14520
    return svn_error_createf(SVN_ERR_WC_LOCKED, err,
14193
 
                             _("Working copy '%s' locked"),
 
14521
                             _("Failed to lock working copy '%s'."),
14194
14522
                             path_for_error_message(wcroot,
14195
14523
                                                    local_relpath,
14196
14524
                                                    scratch_pool));
14249
14577
 
14250
14578
  SVN_WC__DB_WITH_TXN(
14251
14579
    wclock_obtain_cb(wcroot, local_relpath, levels_to_lock, steal_lock,
14252
 
                     scratch_pool),
 
14580
                     db->enforce_empty_wq, scratch_pool),
14253
14581
    wcroot);
14254
14582
  return SVN_NO_ERROR;
14255
14583
}
14440
14768
 
14441
14769
/* Like svn_wc__db_wclock_owns_lock() but taking WCROOT+LOCAL_RELPATH instead
14442
14770
   of DB+LOCAL_ABSPATH.  */
14443
 
static svn_error_t *
14444
 
wclock_owns_lock(svn_boolean_t *own_lock,
14445
 
                 svn_wc__db_wcroot_t *wcroot,
14446
 
                 const char *local_relpath,
14447
 
                 svn_boolean_t exact,
14448
 
                 apr_pool_t *scratch_pool)
 
14771
svn_error_t *
 
14772
svn_wc__db_wclock_owns_lock_internal(svn_boolean_t *own_lock,
 
14773
                                     svn_wc__db_wcroot_t *wcroot,
 
14774
                                     const char *local_relpath,
 
14775
                                     svn_boolean_t exact,
 
14776
                                     apr_pool_t *scratch_pool)
14449
14777
{
14450
14778
  apr_array_header_t *owned_locks;
14451
14779
  int lock_level;
14512
14840
 
14513
14841
  VERIFY_USABLE_WCROOT(wcroot);
14514
14842
 
14515
 
  SVN_ERR(wclock_owns_lock(own_lock, wcroot, local_relpath, exact,
14516
 
                           scratch_pool));
 
14843
  SVN_ERR(svn_wc__db_wclock_owns_lock_internal(own_lock, wcroot, local_relpath,
 
14844
                                               exact, scratch_pool));
14517
14845
 
14518
14846
  return SVN_NO_ERROR;
14519
14847
}
14629
14957
  return SVN_NO_ERROR;
14630
14958
}
14631
14959
 
 
14960
/* Helper for svn_wc__db_op_make_copy_internal */
 
14961
static svn_error_t *
 
14962
db_move_moved_to(svn_wc__db_wcroot_t *wcroot,
 
14963
                 const char *src1_relpath,
 
14964
                 int src1_op_depth,
 
14965
                 const char *src2_relpath,
 
14966
                 int src2_op_depth,
 
14967
                 const char *dst_relpath,
 
14968
                 apr_pool_t *scratch_pool)
 
14969
{
 
14970
  svn_sqlite__stmt_t *stmt;
 
14971
  int affected_rows;
 
14972
 
 
14973
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
14974
                                     STMT_UPDATE_MOVED_TO_RELPATH));
 
14975
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
 
14976
                            src1_relpath, src1_op_depth));
 
14977
  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
14978
 
 
14979
  if (affected_rows == 1)
 
14980
    {
 
14981
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
14982
                                     STMT_UPDATE_MOVED_TO_RELPATH));
 
14983
      SVN_ERR(svn_sqlite__bindf(stmt, "isds", wcroot->wc_id,
 
14984
                                src2_relpath, src2_op_depth,
 
14985
                                dst_relpath));
 
14986
      SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
14987
    }
 
14988
  if (affected_rows != 1)
 
14989
    return svn_error_create(SVN_ERR_WC_PATH_NOT_FOUND, NULL, NULL);
 
14990
 
 
14991
  return SVN_NO_ERROR;
 
14992
}
 
14993
 
 
14994
static svn_error_t *
 
14995
db_move_moved_to_down_recursive(svn_wc__db_wcroot_t *wcroot,
 
14996
                                const char *local_relpath,
 
14997
                                int new_shadow_layer,
 
14998
                                apr_pool_t *scratch_pool)
 
14999
{
 
15000
  svn_sqlite__stmt_t *stmt;
 
15001
  svn_boolean_t have_row;
 
15002
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
15003
 
 
15004
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
15005
                        STMT_SELECT_MOVED_DESCENDANTS_SRC));
 
15006
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
 
15007
                            new_shadow_layer));
 
15008
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
15009
 
 
15010
  while (have_row)
 
15011
    {
 
15012
      int del_op_depth;
 
15013
      const char *src_relpath;
 
15014
      const char *dst_relpath;
 
15015
      svn_error_t *err;
 
15016
 
 
15017
      svn_pool_clear(iterpool);
 
15018
 
 
15019
      del_op_depth = svn_sqlite__column_int(stmt, 0);
 
15020
      src_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
 
15021
      dst_relpath = svn_sqlite__column_text(stmt, 4, iterpool);
 
15022
 
 
15023
      err = svn_error_trace(
 
15024
               db_move_moved_to(
 
15025
                             wcroot,
 
15026
                             src_relpath, del_op_depth,
 
15027
                             src_relpath, new_shadow_layer,
 
15028
                             dst_relpath, iterpool));
 
15029
 
 
15030
      if (err)
 
15031
        return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 
15032
 
 
15033
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
15034
    }
 
15035
 
 
15036
  SVN_ERR(svn_sqlite__reset(stmt));
 
15037
 
 
15038
  return SVN_NO_ERROR;
 
15039
}
 
15040
 
14632
15041
 
14633
15042
/* The body of svn_wc__db_temp_op_make_copy().  This is
14634
15043
   used by the update editor when deleting a base node tree would be a
14666
15075
static svn_error_t *
14667
15076
make_copy_txn(svn_wc__db_wcroot_t *wcroot,
14668
15077
              const char *local_relpath,
14669
 
              int op_depth,
14670
 
              const svn_skel_t *conflicts,
14671
 
              const svn_skel_t *work_items,
 
15078
              apr_int64_t last_repos_id,
 
15079
              const char *last_repos_relpath,
 
15080
              svn_revnum_t last_revision,
 
15081
              int last_op_depth,
 
15082
              svn_boolean_t shadowed,
 
15083
              int root_shadow_depth,
14672
15084
              apr_pool_t *scratch_pool)
14673
15085
{
14674
15086
  svn_sqlite__stmt_t *stmt;
 
15087
  svn_boolean_t have_row = FALSE;
 
15088
  svn_revnum_t revision;
 
15089
  apr_int64_t repos_id;
 
15090
  const char *repos_relpath;
 
15091
  svn_node_kind_t kind;
 
15092
  int op_depth = relpath_depth(local_relpath);
 
15093
 
 
15094
  if (last_op_depth != op_depth)
 
15095
    {
 
15096
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
15097
                                        STMT_SELECT_DEPTH_NODE));
 
15098
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
 
15099
                                op_depth));
 
15100
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
15101
      SVN_ERR(svn_sqlite__reset(stmt));
 
15102
      if (have_row)
 
15103
        shadowed = TRUE;
 
15104
    }
 
15105
 
 
15106
  SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &kind, &revision,
 
15107
                                            &repos_relpath, &repos_id, NULL,
 
15108
                                            NULL, NULL, NULL, NULL, NULL, NULL,
 
15109
                                            NULL, NULL, NULL,
 
15110
                                            wcroot, local_relpath,
 
15111
                                            scratch_pool, scratch_pool));
 
15112
 
 
15113
  if (last_repos_relpath
 
15114
      && repos_id == last_repos_id
 
15115
      && revision == last_revision)
 
15116
    {
 
15117
      const char *name = svn_relpath_skip_ancestor(last_repos_relpath,
 
15118
                                                   repos_relpath);
 
15119
 
 
15120
      if (strcmp(name, svn_relpath_basename(local_relpath, NULL)) == 0)
 
15121
        op_depth = last_op_depth;
 
15122
    }
 
15123
 
 
15124
  /* Can we add a new copy node at the wanted op-depth? */
 
15125
  if (!have_row || op_depth == last_op_depth)
 
15126
    {
 
15127
      int i;
 
15128
 
 
15129
      SVN_ERR(svn_sqlite__get_statement(
 
15130
                    &stmt, wcroot->sdb,
 
15131
                    STMT_INSERT_WORKING_NODE_FROM_BASE_COPY));
 
15132
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
 
15133
                                op_depth));
 
15134
      SVN_ERR(svn_sqlite__step_done(stmt));
 
15135
 
 
15136
      if (shadowed)
 
15137
        SVN_ERR(db_extend_parent_delete(wcroot, local_relpath, kind,
 
15138
                                        op_depth, scratch_pool));
 
15139
 
 
15140
      if (kind == svn_node_dir)
 
15141
        {
 
15142
          const apr_array_header_t *children;
 
15143
          apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
15144
 
 
15145
          SVN_ERR(gather_children(&children, wcroot, local_relpath,
 
15146
                                  STMT_SELECT_OP_DEPTH_CHILDREN, 0,
 
15147
                                  scratch_pool, iterpool));
 
15148
 
 
15149
          for (i = 0; i < children->nelts; i++)
 
15150
            {
 
15151
              const char *name = APR_ARRAY_IDX(children, i, const char *);
 
15152
              const char *copy_relpath;
 
15153
 
 
15154
              svn_pool_clear(iterpool);
 
15155
 
 
15156
              copy_relpath = svn_relpath_join(local_relpath, name, iterpool);
 
15157
 
 
15158
              SVN_ERR(make_copy_txn(wcroot, copy_relpath,
 
15159
                                    repos_id, repos_relpath, revision,
 
15160
                                    op_depth, shadowed, root_shadow_depth,
 
15161
                                    scratch_pool));
 
15162
            }
 
15163
          svn_pool_destroy(iterpool);
 
15164
        }
 
15165
    }
 
15166
  else
 
15167
    {
 
15168
      /* Auch... we can't make a copy of whatever comes deeper, as this
 
15169
         op-depth is already filled by something else. Let's hope
 
15170
         the user doesn't mind.
 
15171
 
 
15172
         Luckily we know that the moves are already moved to the shadowing
 
15173
         layer, so we can just remove dangling base-deletes if there are
 
15174
         any.
 
15175
       */
 
15176
      /* BASE_DELETED may be at op_depth, so let's use last_op_depth! */
 
15177
      SVN_ERR(db_move_moved_to_down_recursive(wcroot, local_relpath,
 
15178
                                              root_shadow_depth,
 
15179
                                              scratch_pool));
 
15180
 
 
15181
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
15182
                    STMT_DELETE_WORKING_BASE_DELETE));
 
15183
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
 
15184
                                last_op_depth));
 
15185
      SVN_ERR(svn_sqlite__step_done(stmt));
 
15186
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
15187
                    STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE));
 
15188
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
 
15189
                                last_op_depth));
 
15190
      SVN_ERR(svn_sqlite__step_done(stmt));
 
15191
    }
 
15192
 
 
15193
  /* Insert a not-present node to mark that we don't know what exists here.
 
15194
 
 
15195
     We do this last (after recursing), to allow the move fix-up code to
 
15196
     see the original moves. */
 
15197
  if (last_op_depth > 0 && last_op_depth != op_depth)
 
15198
    {
 
15199
      insert_working_baton_t iwb;
 
15200
 
 
15201
      blank_iwb(&iwb);
 
15202
      iwb.presence = svn_wc__db_status_not_present;
 
15203
      iwb.op_depth = last_op_depth;
 
15204
 
 
15205
      iwb.original_repos_id = repos_id;
 
15206
      iwb.original_repos_relpath = repos_relpath;
 
15207
      iwb.original_revnum = revision;
 
15208
      iwb.kind = kind;
 
15209
 
 
15210
      SVN_ERR(insert_working_node(&iwb, wcroot, local_relpath, scratch_pool));
 
15211
    }
 
15212
 
 
15213
  return SVN_NO_ERROR;
 
15214
}
 
15215
 
 
15216
 
 
15217
svn_error_t *
 
15218
svn_wc__db_op_make_copy_internal(svn_wc__db_wcroot_t *wcroot,
 
15219
                                 const char *local_relpath,
 
15220
                                 svn_boolean_t move_move_info,
 
15221
                                 const svn_skel_t *conflicts,
 
15222
                                 const svn_skel_t *work_items,
 
15223
                                 apr_pool_t *scratch_pool)
 
15224
{
 
15225
  svn_sqlite__stmt_t *stmt;
14675
15226
  svn_boolean_t have_row;
14676
 
  svn_boolean_t add_working_base_deleted = FALSE;
14677
 
  svn_boolean_t remove_working = FALSE;
14678
 
  const apr_array_header_t *children;
14679
 
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
14680
 
  int i;
 
15227
  int op_depth = -1;
14681
15228
 
 
15229
  /* The update editor is supposed to call this function when there is
 
15230
     no working node for LOCAL_ABSPATH. */
14682
15231
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
14683
 
                                    STMT_SELECT_LOWEST_WORKING_NODE));
14684
 
  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0));
 
15232
                                    STMT_SELECT_WORKING_NODE));
 
15233
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
14685
15234
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
14686
 
 
14687
 
  if (have_row)
14688
 
    {
14689
 
      svn_wc__db_status_t working_status;
14690
 
      int working_op_depth;
14691
 
 
14692
 
      working_status = svn_sqlite__column_token(stmt, 1, presence_map);
14693
 
      working_op_depth = svn_sqlite__column_int(stmt, 0);
14694
 
      SVN_ERR(svn_sqlite__reset(stmt));
14695
 
 
14696
 
      SVN_ERR_ASSERT(working_status == svn_wc__db_status_normal
14697
 
                     || working_status == svn_wc__db_status_base_deleted
14698
 
                     || working_status == svn_wc__db_status_not_present
14699
 
                     || working_status == svn_wc__db_status_incomplete);
14700
 
 
14701
 
      /* Only change nodes in the layers where we are creating the copy.
14702
 
         Deletes in higher layers will just apply to the copy */
14703
 
      if (working_op_depth <= op_depth)
14704
 
        {
14705
 
          add_working_base_deleted = TRUE;
14706
 
 
14707
 
          if (working_status == svn_wc__db_status_base_deleted)
14708
 
            remove_working = TRUE;
14709
 
        }
14710
 
    }
14711
 
  else
14712
 
    SVN_ERR(svn_sqlite__reset(stmt));
14713
 
 
14714
 
  if (remove_working)
14715
 
    {
14716
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
14717
 
                                        STMT_DELETE_LOWEST_WORKING_NODE));
14718
 
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
14719
 
      SVN_ERR(svn_sqlite__step_done(stmt));
14720
 
    }
14721
 
 
14722
 
  if (add_working_base_deleted)
14723
 
    {
14724
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
14725
 
                                        STMT_INSERT_DELETE_FROM_BASE));
14726
 
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
14727
 
                                op_depth));
14728
 
      SVN_ERR(svn_sqlite__step_done(stmt));
14729
 
    }
14730
 
  else
14731
 
    {
14732
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
14733
 
                                      STMT_INSERT_WORKING_NODE_FROM_BASE_COPY));
14734
 
      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
14735
 
                                op_depth));
14736
 
      SVN_ERR(svn_sqlite__step_done(stmt));
14737
 
    }
14738
 
 
14739
 
  /* Get the BASE children, as WORKING children don't need modifications */
14740
 
  SVN_ERR(gather_repo_children(&children, wcroot, local_relpath,
14741
 
                               0, scratch_pool, iterpool));
14742
 
 
14743
 
  for (i = 0; i < children->nelts; i++)
14744
 
    {
14745
 
      const char *name = APR_ARRAY_IDX(children, i, const char *);
14746
 
      const char *copy_relpath;
14747
 
 
14748
 
      svn_pool_clear(iterpool);
14749
 
 
14750
 
      copy_relpath = svn_relpath_join(local_relpath, name, iterpool);
14751
 
 
14752
 
      SVN_ERR(make_copy_txn(wcroot, copy_relpath, op_depth, NULL, NULL,
14753
 
                            iterpool));
14754
 
    }
14755
 
 
14756
 
  SVN_ERR(flush_entries(wcroot, svn_dirent_join(wcroot->abspath, local_relpath,
14757
 
                                                iterpool),
14758
 
                                                svn_depth_empty, iterpool));
 
15235
  if (have_row)
 
15236
    op_depth = svn_sqlite__column_int(stmt, 0);
 
15237
  SVN_ERR(svn_sqlite__reset(stmt));
 
15238
 
 
15239
  if (have_row)
 
15240
    {
 
15241
      if (op_depth == relpath_depth(local_relpath))
 
15242
        return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
 
15243
                             _("Modification of '%s' already exists"),
 
15244
                             path_for_error_message(wcroot,
 
15245
                                                    local_relpath,
 
15246
                                                    scratch_pool));
 
15247
 
 
15248
      /* We have a working layer, but not one at the op-depth of local-relpath,
 
15249
         so we can create a copy by just copying the lower layer */
 
15250
 
 
15251
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
 
15252
                                        STMT_COPY_OP_DEPTH_RECURSIVE));
 
15253
      SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id, local_relpath,
 
15254
                                op_depth, relpath_depth(local_relpath)));
 
15255
      SVN_ERR(svn_sqlite__step_done(stmt));
 
15256
    }
 
15257
  else
 
15258
    {
 
15259
      int affected_rows;
 
15260
 
 
15261
      op_depth = relpath_depth(local_relpath);
 
15262
      /* We don't allow copies to contain server-excluded nodes;
 
15263
         the update editor is going to have to bail out. */
 
15264
      SVN_ERR(catch_copy_of_server_excluded(wcroot, local_relpath,
 
15265
                                            scratch_pool));
 
15266
 
 
15267
      /* Insert a shadowing layer */
 
15268
      SVN_ERR(svn_sqlite__get_statement(
 
15269
                        &stmt, wcroot->sdb,
 
15270
                        STMT_INSERT_DELETE_FROM_NODE_RECURSIVE));
 
15271
 
 
15272
      /* As we are keeping whatever is below, move the*/
 
15273
 
 
15274
      SVN_ERR(svn_sqlite__bindf(stmt, "isdd",
 
15275
                                wcroot->wc_id, local_relpath,
 
15276
                                0, op_depth));
 
15277
      SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
15278
      SVN_ERR_ASSERT(affected_rows > 0);
 
15279
 
 
15280
      if (!move_move_info)
 
15281
        SVN_ERR(db_move_moved_to_down_recursive(wcroot, local_relpath,
 
15282
                                                op_depth, scratch_pool));
 
15283
 
 
15284
 
 
15285
      SVN_ERR(make_copy_txn(wcroot, local_relpath,
 
15286
                            INVALID_REPOS_ID, NULL, SVN_INVALID_REVNUM,
 
15287
                            op_depth, FALSE, op_depth,
 
15288
                            scratch_pool));
 
15289
    }
14759
15290
 
14760
15291
  if (conflicts)
14761
15292
    SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
14762
 
                                              conflicts, iterpool));
14763
 
 
14764
 
  SVN_ERR(add_work_items(wcroot->sdb, work_items, iterpool));
14765
 
 
14766
 
  svn_pool_destroy(iterpool);
 
15293
                                              conflicts, scratch_pool));
 
15294
 
 
15295
  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
14767
15296
 
14768
15297
  return SVN_NO_ERROR;
14769
15298
}
14778
15307
{
14779
15308
  svn_wc__db_wcroot_t *wcroot;
14780
15309
  const char *local_relpath;
14781
 
  svn_sqlite__stmt_t *stmt;
14782
 
  svn_boolean_t have_row;
14783
15310
 
14784
15311
  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
14785
15312
 
14787
15314
                              local_abspath, scratch_pool, scratch_pool));
14788
15315
  VERIFY_USABLE_WCROOT(wcroot);
14789
15316
 
14790
 
  /* The update editor is supposed to call this function when there is
14791
 
     no working node for LOCAL_ABSPATH. */
14792
 
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
14793
 
                                    STMT_SELECT_WORKING_NODE));
14794
 
  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
14795
 
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
14796
 
  SVN_ERR(svn_sqlite__reset(stmt));
14797
 
  if (have_row)
14798
 
    return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
14799
 
                             _("Modification of '%s' already exists"),
14800
 
                             path_for_error_message(wcroot,
14801
 
                                                    local_relpath,
14802
 
                                                    scratch_pool));
14803
 
 
14804
 
  /* We don't allow copies to contain server-excluded nodes;
14805
 
     the update editor is going to have to bail out. */
14806
 
  SVN_ERR(catch_copy_of_server_excluded(wcroot, local_relpath, scratch_pool));
14807
 
 
14808
15317
  SVN_WC__DB_WITH_TXN(
14809
 
    make_copy_txn(wcroot, local_relpath,
14810
 
                  relpath_depth(local_relpath), conflicts, work_items,
14811
 
                  scratch_pool),
 
15318
    svn_wc__db_op_make_copy_internal(wcroot, local_relpath, FALSE,
 
15319
                                     conflicts, work_items,
 
15320
                                     scratch_pool),
14812
15321
    wcroot);
14813
15322
 
 
15323
  SVN_ERR(flush_entries(wcroot, local_abspath,
 
15324
                        svn_depth_infinity, scratch_pool));
 
15325
 
14814
15326
  return SVN_NO_ERROR;
14815
15327
}
14816
15328
 
15017
15529
         does not match the given trailing URL then the whole working
15018
15530
         copy is switched. */
15019
15531
 
15020
 
      SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, NULL, wcroot->sdb,
 
15532
      SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, NULL, wcroot,
15021
15533
                                          repos_id, scratch_pool));
15022
15534
      url = svn_path_url_add_component2(repos_root_url, repos_relpath,
15023
15535
                                        scratch_pool);
15108
15620
  return SVN_NO_ERROR;
15109
15621
}
15110
15622
 
15111
 
/* Like svn_wc__db_has_local_mods(),
 
15623
/* Like svn_wc__db_has_db_mods(),
15112
15624
 * but accepts a WCROOT/LOCAL_RELPATH pair.
15113
15625
 * ### This needs a DB as well as a WCROOT/RELPATH pair... */
15114
15626
static svn_error_t *
15115
 
has_local_mods(svn_boolean_t *is_modified,
15116
 
               svn_wc__db_wcroot_t *wcroot,
15117
 
               const char *local_relpath,
15118
 
               svn_wc__db_t *db,
15119
 
               svn_cancel_func_t cancel_func,
15120
 
               void *cancel_baton,
15121
 
               apr_pool_t *scratch_pool)
 
15627
has_db_mods(svn_boolean_t *is_modified,
 
15628
            svn_wc__db_wcroot_t *wcroot,
 
15629
            const char *local_relpath,
 
15630
            apr_pool_t *scratch_pool)
15122
15631
{
15123
15632
  svn_sqlite__stmt_t *stmt;
15124
15633
 
15130
15639
  SVN_ERR(svn_sqlite__step(is_modified, stmt));
15131
15640
  SVN_ERR(svn_sqlite__reset(stmt));
15132
15641
 
15133
 
  if (cancel_func)
15134
 
    SVN_ERR(cancel_func(cancel_baton));
15135
 
 
15136
15642
  if (! *is_modified)
15137
15643
    {
15138
15644
      /* Check for property modifications. */
15142
15648
      /* If this query returns a row, the working copy is modified. */
15143
15649
      SVN_ERR(svn_sqlite__step(is_modified, stmt));
15144
15650
      SVN_ERR(svn_sqlite__reset(stmt));
15145
 
 
15146
 
      if (cancel_func)
15147
 
        SVN_ERR(cancel_func(cancel_baton));
15148
 
    }
15149
 
 
15150
 
  if (! *is_modified)
15151
 
    {
15152
 
      apr_pool_t *iterpool = NULL;
15153
 
      svn_boolean_t have_row;
15154
 
 
15155
 
      /* Check for text modifications. */
15156
 
      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
15157
 
                                        STMT_SELECT_BASE_FILES_RECURSIVE));
15158
 
      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
15159
 
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
15160
 
      if (have_row)
15161
 
        iterpool = svn_pool_create(scratch_pool);
15162
 
      while (have_row)
15163
 
        {
15164
 
          const char *node_abspath;
15165
 
          svn_filesize_t recorded_size;
15166
 
          apr_time_t recorded_time;
15167
 
          svn_boolean_t skip_check = FALSE;
15168
 
          svn_error_t *err;
15169
 
 
15170
 
          if (cancel_func)
15171
 
            {
15172
 
              err = cancel_func(cancel_baton);
15173
 
              if (err)
15174
 
                return svn_error_trace(svn_error_compose_create(
15175
 
                                                    err,
15176
 
                                                    svn_sqlite__reset(stmt)));
15177
 
            }
15178
 
 
15179
 
          svn_pool_clear(iterpool);
15180
 
 
15181
 
          node_abspath = svn_dirent_join(wcroot->abspath,
15182
 
                                         svn_sqlite__column_text(stmt, 0,
15183
 
                                                                 iterpool),
15184
 
                                         iterpool);
15185
 
 
15186
 
          recorded_size = get_recorded_size(stmt, 1);
15187
 
          recorded_time = svn_sqlite__column_int64(stmt, 2);
15188
 
 
15189
 
          if (recorded_size != SVN_INVALID_FILESIZE
15190
 
              && recorded_time != 0)
15191
 
            {
15192
 
              const svn_io_dirent2_t *dirent;
15193
 
 
15194
 
              err = svn_io_stat_dirent2(&dirent, node_abspath, FALSE, TRUE,
15195
 
                                        iterpool, iterpool);
15196
 
              if (err)
15197
 
                return svn_error_trace(svn_error_compose_create(
15198
 
                                                    err,
15199
 
                                                    svn_sqlite__reset(stmt)));
15200
 
 
15201
 
              if (dirent->kind != svn_node_file)
15202
 
                {
15203
 
                  *is_modified = TRUE; /* Missing or obstruction */
15204
 
                  break;
15205
 
                }
15206
 
              else if (dirent->filesize == recorded_size
15207
 
                       && dirent->mtime == recorded_time)
15208
 
                {
15209
 
                  /* The file is not modified */
15210
 
                  skip_check = TRUE;
15211
 
                }
15212
 
            }
15213
 
 
15214
 
          if (! skip_check)
15215
 
            {
15216
 
              err = svn_wc__internal_file_modified_p(is_modified,
15217
 
                                                     db, node_abspath,
15218
 
                                                     FALSE, iterpool);
15219
 
 
15220
 
              if (err)
15221
 
                return svn_error_trace(svn_error_compose_create(
15222
 
                                                    err,
15223
 
                                                    svn_sqlite__reset(stmt)));
15224
 
 
15225
 
              if (*is_modified)
15226
 
                break;
15227
 
            }
15228
 
 
15229
 
          SVN_ERR(svn_sqlite__step(&have_row, stmt));
15230
 
        }
15231
 
      if (iterpool)
15232
 
        svn_pool_destroy(iterpool);
15233
 
 
15234
 
      SVN_ERR(svn_sqlite__reset(stmt));
15235
15651
    }
15236
15652
 
15237
15653
  return SVN_NO_ERROR;
15239
15655
 
15240
15656
 
15241
15657
svn_error_t *
15242
 
svn_wc__db_has_local_mods(svn_boolean_t *is_modified,
15243
 
                          svn_wc__db_t *db,
15244
 
                          const char *local_abspath,
15245
 
                          svn_cancel_func_t cancel_func,
15246
 
                          void *cancel_baton,
15247
 
                          apr_pool_t *scratch_pool)
 
15658
svn_wc__db_has_db_mods(svn_boolean_t *is_modified,
 
15659
                       svn_wc__db_t *db,
 
15660
                       const char *local_abspath,
 
15661
                       apr_pool_t *scratch_pool)
15248
15662
{
15249
15663
  svn_wc__db_wcroot_t *wcroot;
15250
15664
  const char *local_relpath;
15256
15670
                                                scratch_pool, scratch_pool));
15257
15671
  VERIFY_USABLE_WCROOT(wcroot);
15258
15672
 
15259
 
  return svn_error_trace(has_local_mods(is_modified, wcroot, local_relpath,
15260
 
                                        db, cancel_func, cancel_baton,
15261
 
                                        scratch_pool));
 
15673
  return svn_error_trace(has_db_mods(is_modified, wcroot, local_relpath,
 
15674
                                     scratch_pool));
15262
15675
}
15263
15676
 
15264
15677
 
15275
15688
                    svn_wc__db_t *db,
15276
15689
                    const char *trail_url,
15277
15690
                    svn_boolean_t committed,
15278
 
                    svn_cancel_func_t cancel_func,
15279
 
                    void *cancel_baton,
15280
15691
                    apr_pool_t *scratch_pool)
15281
15692
{
15282
15693
  svn_error_t *err;
15296
15707
  SVN_ERR(get_min_max_revisions(min_revision, max_revision, wcroot,
15297
15708
                                local_relpath, committed, scratch_pool));
15298
15709
 
15299
 
  if (cancel_func)
15300
 
    SVN_ERR(cancel_func(cancel_baton));
15301
 
 
15302
15710
  /* Determine sparseness. */
15303
15711
  SVN_ERR(is_sparse_checkout_internal(is_sparse_checkout, wcroot,
15304
15712
                                      local_relpath, scratch_pool));
15305
15713
 
15306
 
  if (cancel_func)
15307
 
    SVN_ERR(cancel_func(cancel_baton));
15308
 
 
15309
15714
  /* Check for switched nodes. */
15310
15715
  {
15311
15716
    err = has_switched_subtrees(is_switched, wcroot, local_relpath,
15321
15726
      }
15322
15727
  }
15323
15728
 
15324
 
  if (cancel_func)
15325
 
    SVN_ERR(cancel_func(cancel_baton));
15326
 
 
15327
 
  /* Check for local mods. */
15328
 
  SVN_ERR(has_local_mods(is_modified, wcroot, local_relpath, db,
15329
 
                         cancel_func, cancel_baton, scratch_pool));
 
15729
  /* Check for db mods. */
 
15730
  SVN_ERR(has_db_mods(is_modified, wcroot, local_relpath, scratch_pool));
15330
15731
 
15331
15732
  return SVN_NO_ERROR;
15332
15733
}
15342
15743
                           const char *local_abspath,
15343
15744
                           const char *trail_url,
15344
15745
                           svn_boolean_t committed,
15345
 
                           svn_cancel_func_t cancel_func,
15346
 
                           void *cancel_baton,
15347
15746
                           apr_pool_t *scratch_pool)
15348
15747
{
15349
15748
  svn_wc__db_wcroot_t *wcroot;
15360
15759
    revision_status_txn(min_revision, max_revision,
15361
15760
                        is_sparse_checkout, is_modified, is_switched,
15362
15761
                        wcroot, local_relpath, db,
15363
 
                        trail_url, committed, cancel_func, cancel_baton,
 
15762
                        trail_url, committed,
15364
15763
                        scratch_pool),
15365
15764
    wcroot);
15366
15765
  return SVN_NO_ERROR;
15406
15805
      if (child_repos_id != last_repos_id)
15407
15806
        {
15408
15807
          svn_error_t *err = svn_wc__db_fetch_repos_info(&last_repos_root_url,
15409
 
                                                         NULL, wcroot->sdb,
 
15808
                                                         NULL, wcroot,
15410
15809
                                                         child_repos_id,
15411
15810
                                                         scratch_pool);
15412
15811
 
15529
15928
  return SVN_NO_ERROR;
15530
15929
}
15531
15930
 
 
15931
 
 
15932
svn_error_t *
 
15933
svn_wc__db_verify_db_full_internal(svn_wc__db_wcroot_t *wcroot,
 
15934
                                   svn_wc__db_verify_cb_t callback,
 
15935
                                   void *baton,
 
15936
                                   apr_pool_t *scratch_pool)
 
15937
{
 
15938
  svn_sqlite__stmt_t *stmt;
 
15939
  svn_boolean_t have_row;
 
15940
  svn_error_t *err = NULL;
 
15941
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
15942
 
 
15943
  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_STATIC_VERIFY));
 
15944
  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
15945
 
 
15946
  while (have_row)
 
15947
    {
 
15948
      const char *local_relpath;
 
15949
      int op_depth = svn_sqlite__column_int(stmt, 1);
 
15950
      int id = svn_sqlite__column_int(stmt, 2);
 
15951
      const char *msg;
 
15952
 
 
15953
      svn_pool_clear(iterpool);
 
15954
 
 
15955
      local_relpath =  svn_sqlite__column_text(stmt, 0, iterpool);
 
15956
      msg = svn_sqlite__column_text(stmt, 3, scratch_pool);
 
15957
 
 
15958
      err = callback(baton, wcroot->abspath, local_relpath, op_depth,
 
15959
                     id, msg, iterpool);
 
15960
 
 
15961
      if (err)
 
15962
        break;
 
15963
 
 
15964
      SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
15965
    }
 
15966
 
 
15967
  svn_pool_destroy(iterpool);
 
15968
 
 
15969
  return svn_error_trace(
 
15970
            svn_error_compose_create(err, svn_sqlite__reset(stmt)));
 
15971
}
 
15972
 
 
15973
svn_error_t *
 
15974
svn_wc__db_verify_db_full(svn_wc__db_t *db,
 
15975
                          const char *wri_abspath,
 
15976
                          svn_wc__db_verify_cb_t callback,
 
15977
                          void *baton,
 
15978
                          apr_pool_t *scratch_pool)
 
15979
{
 
15980
  svn_wc__db_wcroot_t *wcroot;
 
15981
  const char *local_relpath;
 
15982
 
 
15983
  SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
 
15984
 
 
15985
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
 
15986
                              wri_abspath, scratch_pool, scratch_pool));
 
15987
  VERIFY_USABLE_WCROOT(wcroot);
 
15988
 
 
15989
  return svn_error_trace(
 
15990
            svn_wc__db_verify_db_full_internal(wcroot, callback, baton,
 
15991
                                               scratch_pool));
 
15992
}
 
15993
 
15532
15994
svn_error_t *
15533
15995
svn_wc__db_bump_format(int *result_format,
15534
15996
                       svn_boolean_t *bumped_format,
15549
16011
  err = svn_wc__db_util_open_db(&sdb, wcroot_abspath, SDB_FILE,
15550
16012
                                svn_sqlite__mode_readwrite,
15551
16013
                                TRUE, /* exclusive */
 
16014
                                0, /* default timeout */
15552
16015
                                NULL, /* my statements */
15553
16016
                                scratch_pool, scratch_pool);
15554
16017
  if (err)
15608
16071
 
15609
16072
  return SVN_NO_ERROR;
15610
16073
}
 
16074
 
 
16075
/* Item queued with svn_wc__db_commit_queue_add */
 
16076
typedef struct commit_queue_item_t
 
16077
{
 
16078
  const char *local_relpath;
 
16079
  svn_boolean_t recurse; /* Use legacy recursion */
 
16080
  svn_boolean_t committed; /* Process the node as committed */
 
16081
  svn_boolean_t remove_lock; /* Remove existing lock on node */
 
16082
  svn_boolean_t remove_changelist; /* Remove changelist on node */
 
16083
 
 
16084
  /* The pristine text checksum. NULL if the old value should be kept
 
16085
     and for directories */
 
16086
  const svn_checksum_t *new_sha1_checksum;
 
16087
 
 
16088
  apr_hash_t *new_dav_cache; /* New DAV cache for the node */
 
16089
} commit_queue_item_t;
 
16090
 
 
16091
/* The queue definition for vn_wc__db_create_commit_queue,
 
16092
   svn_wc__db_commit_queue_add and finally svn_wc__db_process_commit_queue */
 
16093
struct svn_wc__db_commit_queue_t
 
16094
{
 
16095
  svn_wc__db_wcroot_t *wcroot; /* Wcroot for ITEMS */
 
16096
  apr_array_header_t *items; /* List of commit_queue_item_t* */
 
16097
  svn_boolean_t have_recurse; /* Is one or more item[x]->recurse TRUE? */
 
16098
};
 
16099
 
 
16100
/* Create a new svn_wc__db_commit_queue_t instance in RESULT_POOL for the
 
16101
   working copy specified with WRI_ABSPATH */
 
16102
svn_error_t *
 
16103
svn_wc__db_create_commit_queue(svn_wc__db_commit_queue_t **queue,
 
16104
                               svn_wc__db_t *db,
 
16105
                               const char *wri_abspath,
 
16106
                               apr_pool_t *result_pool,
 
16107
                               apr_pool_t *scratch_pool)
 
16108
{
 
16109
  svn_wc__db_wcroot_t *wcroot;
 
16110
  const char *local_relpath;
 
16111
  svn_wc__db_commit_queue_t *q;
 
16112
 
 
16113
  SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
 
16114
 
 
16115
  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
 
16116
                              wri_abspath, result_pool, scratch_pool));
 
16117
  VERIFY_USABLE_WCROOT(wcroot);
 
16118
 
 
16119
  q = apr_pcalloc(result_pool, sizeof(*q));
 
16120
 
 
16121
  SVN_ERR_ASSERT(wcroot->sdb);
 
16122
 
 
16123
  q->wcroot = wcroot;
 
16124
  q->items = apr_array_make(result_pool, 64,
 
16125
                            sizeof(commit_queue_item_t*));
 
16126
  q->have_recurse = FALSE;
 
16127
 
 
16128
  *queue = q;
 
16129
  return SVN_NO_ERROR;
 
16130
}
 
16131
 
 
16132
svn_error_t *
 
16133
svn_wc__db_commit_queue_add(svn_wc__db_commit_queue_t *queue,
 
16134
                            const char *local_abspath,
 
16135
                            svn_boolean_t recurse,
 
16136
                            svn_boolean_t is_commited,
 
16137
                            svn_boolean_t remove_lock,
 
16138
                            svn_boolean_t remove_changelist,
 
16139
                            const svn_checksum_t *new_sha1_checksum,
 
16140
                            apr_hash_t *new_dav_cache,
 
16141
                            apr_pool_t *result_pool,
 
16142
                            apr_pool_t *scratch_pool)
 
16143
{
 
16144
  commit_queue_item_t *cqi;
 
16145
  const char *local_relpath;
 
16146
 
 
16147
  local_relpath = svn_dirent_skip_ancestor(queue->wcroot->abspath,
 
16148
                                           local_abspath);
 
16149
 
 
16150
  if (! local_relpath)
 
16151
    return svn_error_createf(
 
16152
                SVN_ERR_WC_PATH_NOT_FOUND, NULL,
 
16153
                _("The path '%s' is not in the working copy '%s'"),
 
16154
                svn_dirent_local_style(local_abspath, scratch_pool),
 
16155
                svn_dirent_local_style(queue->wcroot->abspath, scratch_pool));
 
16156
 
 
16157
  cqi = apr_pcalloc(result_pool, sizeof(*cqi));
 
16158
  cqi->local_relpath = local_relpath;
 
16159
  cqi->recurse = recurse;
 
16160
  cqi->committed = is_commited;
 
16161
  cqi->remove_lock = remove_lock;
 
16162
  cqi->remove_changelist = remove_changelist;
 
16163
  cqi->new_sha1_checksum = new_sha1_checksum;
 
16164
  cqi->new_dav_cache = new_dav_cache;
 
16165
 
 
16166
  queue->have_recurse |= recurse;
 
16167
 
 
16168
  APR_ARRAY_PUSH(queue->items, commit_queue_item_t *) = cqi;
 
16169
  return SVN_NO_ERROR;
 
16170
}
 
16171
 
 
16172
/*** Finishing updates and commits. ***/
 
16173
 
 
16174
/* Post process an item that is committed in the repository. Collapse layers into
 
16175
 * BASE. Queue work items that will finish a commit of the file or directory
 
16176
 * LOCAL_ABSPATH in DB:
 
16177
 */
 
16178
static svn_error_t *
 
16179
process_committed_leaf(svn_wc__db_t *db,
 
16180
                       svn_wc__db_wcroot_t *wcroot,
 
16181
                       const char *local_relpath,
 
16182
                       svn_boolean_t via_recurse,
 
16183
                       svn_wc__db_status_t status,
 
16184
                       svn_node_kind_t kind,
 
16185
                       svn_boolean_t prop_mods,
 
16186
                       const svn_checksum_t *old_checksum,
 
16187
                       svn_revnum_t new_revnum,
 
16188
                       apr_time_t new_changed_date,
 
16189
                       const char *new_changed_author,
 
16190
                       apr_hash_t *new_dav_cache,
 
16191
                       svn_boolean_t remove_lock,
 
16192
                       svn_boolean_t remove_changelist,
 
16193
                       const svn_checksum_t *checksum,
 
16194
                       apr_pool_t *scratch_pool)
 
16195
{
 
16196
  svn_revnum_t new_changed_rev = new_revnum;
 
16197
  svn_skel_t *work_item = NULL;
 
16198
 
 
16199
  {
 
16200
    const char *lock_relpath;
 
16201
    svn_boolean_t locked;
 
16202
 
 
16203
    if (kind == svn_node_dir)
 
16204
      lock_relpath = local_relpath;
 
16205
    else
 
16206
      lock_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
 
16207
 
 
16208
    SVN_ERR(svn_wc__db_wclock_owns_lock_internal(&locked, wcroot,
 
16209
                                                 lock_relpath, FALSE,
 
16210
                                                 scratch_pool));
 
16211
 
 
16212
    if (!locked)
 
16213
      return svn_error_createf(SVN_ERR_WC_NOT_LOCKED, NULL,
 
16214
                             _("No write-lock in '%s'"),
 
16215
                             path_for_error_message(wcroot, local_relpath,
 
16216
                                                    scratch_pool));
 
16217
 
 
16218
    SVN_ERR(flush_entries(wcroot, lock_relpath, svn_depth_empty,
 
16219
                          scratch_pool));
 
16220
  }
 
16221
 
 
16222
  if (status == svn_wc__db_status_not_present)
 
16223
    {
 
16224
      /* We are committing the leaf of a copy operation.
 
16225
         We leave the not-present marker to allow pulling in excluded
 
16226
         children of a copy.
 
16227
 
 
16228
         The next update will remove the not-present marker. */
 
16229
 
 
16230
      return SVN_NO_ERROR;
 
16231
    }
 
16232
 
 
16233
  SVN_ERR_ASSERT(status == svn_wc__db_status_normal
 
16234
                 || status == svn_wc__db_status_incomplete
 
16235
                 || status == svn_wc__db_status_added
 
16236
                 || status == svn_wc__db_status_deleted);
 
16237
 
 
16238
  if (kind != svn_node_dir
 
16239
      && status != svn_wc__db_status_deleted)
 
16240
    {
 
16241
      /* If we sent a delta (meaning: post-copy modification),
 
16242
         then this file will appear in the queue and so we should have
 
16243
         its checksum already. */
 
16244
      if (checksum == NULL)
 
16245
        {
 
16246
          /* It was copied and not modified. We must have a text
 
16247
             base for it. And the node should have a checksum. */
 
16248
          SVN_ERR_ASSERT(old_checksum != NULL);
 
16249
 
 
16250
          checksum = old_checksum;
 
16251
 
 
16252
          /* Is the node completely unmodified and are we recursing? */
 
16253
          if (via_recurse && !prop_mods)
 
16254
            {
 
16255
              /* If a copied node itself is not modified, but the op_root of
 
16256
                 the copy is committed we have to make sure that changed_rev,
 
16257
                 changed_date and changed_author don't change or the working
 
16258
                 copy used for committing will show different last modified
 
16259
                 information then a clean checkout of exactly the same
 
16260
                 revisions. (Issue #3676) */
 
16261
 
 
16262
              SVN_ERR(svn_wc__db_read_info_internal(
 
16263
                                           NULL, NULL, NULL, NULL, NULL,
 
16264
                                           &new_changed_rev,
 
16265
                                           &new_changed_date,
 
16266
                                           &new_changed_author, NULL, NULL,
 
16267
                                           NULL, NULL, NULL, NULL, NULL,
 
16268
                                           NULL, NULL, NULL, NULL,
 
16269
                                           NULL, NULL, NULL, NULL,
 
16270
                                           NULL, NULL,
 
16271
                                           wcroot, local_relpath,
 
16272
                                           scratch_pool, scratch_pool));
 
16273
            }
 
16274
        }
 
16275
 
 
16276
      SVN_ERR(svn_wc__wq_build_file_commit(&work_item,
 
16277
                                           db, svn_dirent_join(wcroot->abspath,
 
16278
                                                               local_relpath,
 
16279
                                                               scratch_pool),
 
16280
                                           prop_mods,
 
16281
                                           scratch_pool, scratch_pool));
 
16282
    }
 
16283
 
 
16284
  /* The new text base will be found in the pristine store by its checksum. */
 
16285
  SVN_ERR(commit_node(wcroot, local_relpath,
 
16286
                      new_revnum, new_changed_rev,
 
16287
                      new_changed_date, new_changed_author,
 
16288
                      checksum,
 
16289
                      new_dav_cache,
 
16290
                      !remove_changelist,
 
16291
                      !remove_lock,
 
16292
                      work_item,
 
16293
                      scratch_pool));
 
16294
 
 
16295
  return SVN_NO_ERROR;
 
16296
}
 
16297
 
 
16298
/** Internal helper for svn_wc_process_committed_queue2().
 
16299
 * Bump a commit item, collapsing local changes with the new repository
 
16300
 * information to a new BASE node.
 
16301
 *
 
16302
 * @a new_date is the (server-side) date of the new revision, or 0.
 
16303
 *
 
16304
 * @a rev_author is the (server-side) author of the new
 
16305
 * revision; it may be @c NULL.
 
16306
 *
 
16307
 * @a new_dav_cache is a hash of all the new dav properties for LOCAL_RELPATH.
 
16308
 *
 
16309
 * If @a remove_lock is set, release any user locks on @a
 
16310
 * local_abspath; otherwise keep them during processing.
 
16311
 *
 
16312
 * If @a remove_changelist is set, clear any changeset assignments
 
16313
 * from @a local_abspath; otherwise, keep such assignments.
 
16314
 *
 
16315
 * If @a new_sha1_checksum is non-NULL, use it to identify the node's pristine
 
16316
 * text.
 
16317
 *
 
16318
 * Set TOP_OF_RECURSE to TRUE to show that this the top of a possibly
 
16319
 * recursive commit operation. (Part of the legacy recurse handling)
 
16320
 */
 
16321
static svn_error_t *
 
16322
process_committed_internal(svn_wc__db_t *db,
 
16323
                           svn_wc__db_wcroot_t *wcroot,
 
16324
                           const char *local_relpath,
 
16325
                           svn_boolean_t recurse,
 
16326
                           svn_boolean_t top_of_recurse,
 
16327
                           svn_revnum_t new_revnum,
 
16328
                           apr_time_t new_date,
 
16329
                           const char *rev_author,
 
16330
                           apr_hash_t *new_dav_cache,
 
16331
                           svn_boolean_t remove_lock,
 
16332
                           svn_boolean_t remove_changelist,
 
16333
                           const svn_checksum_t *new_sha1_checksum,
 
16334
                           apr_hash_t *items_by_relpath,
 
16335
                           apr_pool_t *scratch_pool)
 
16336
{
 
16337
  svn_wc__db_status_t status;
 
16338
  svn_node_kind_t kind;
 
16339
  const svn_checksum_t *old_checksum;
 
16340
  svn_boolean_t prop_mods;
 
16341
 
 
16342
  SVN_ERR(svn_wc__db_read_info_internal(&status, &kind, NULL, NULL, NULL, NULL, NULL,
 
16343
                                        NULL, NULL, &old_checksum, NULL, NULL,
 
16344
                                        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
16345
                                        NULL, &prop_mods, NULL, NULL, NULL,
 
16346
                                        wcroot, local_relpath,
 
16347
                                        scratch_pool, scratch_pool));
 
16348
 
 
16349
  /* NOTE: be wary of making crazy semantic changes in this function, since
 
16350
     svn_wc_process_committed4() calls this.  */
 
16351
 
 
16352
  SVN_ERR(process_committed_leaf(db, wcroot, local_relpath, !top_of_recurse,
 
16353
                                 status, kind, prop_mods, old_checksum,
 
16354
                                 new_revnum, new_date, rev_author,
 
16355
                                 new_dav_cache,
 
16356
                                 remove_lock, remove_changelist,
 
16357
                                 new_sha1_checksum,
 
16358
                                 scratch_pool));
 
16359
 
 
16360
  /* Only check for recursion on nodes that have children */
 
16361
  if (kind != svn_node_dir
 
16362
      || status == svn_wc__db_status_not_present
 
16363
      || status == svn_wc__db_status_excluded
 
16364
      || status == svn_wc__db_status_server_excluded
 
16365
      /* Node deleted -> then no longer a directory */
 
16366
      || status == svn_wc__db_status_deleted)
 
16367
    {
 
16368
      return SVN_NO_ERROR;
 
16369
    }
 
16370
 
 
16371
  if (recurse)
 
16372
    {
 
16373
      const apr_array_header_t *children;
 
16374
      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
16375
      int i;
 
16376
 
 
16377
      /* Read PATH's entries;  this is the absolute path. */
 
16378
      SVN_ERR(gather_children(&children, wcroot, local_relpath,
 
16379
                              STMT_SELECT_NODE_CHILDREN, -1,
 
16380
                              scratch_pool, iterpool));
 
16381
 
 
16382
      /* Recursively loop over all children. */
 
16383
      for (i = 0; i < children->nelts; i++)
 
16384
        {
 
16385
          const char *name = APR_ARRAY_IDX(children, i, const char *);
 
16386
          const char *this_relpath;
 
16387
          const commit_queue_item_t *cqi;
 
16388
 
 
16389
          svn_pool_clear(iterpool);
 
16390
 
 
16391
          this_relpath = svn_dirent_join(local_relpath, name, iterpool);
 
16392
 
 
16393
          new_sha1_checksum = NULL;
 
16394
          cqi = svn_hash_gets(items_by_relpath, this_relpath);
 
16395
 
 
16396
          if (cqi != NULL)
 
16397
            new_sha1_checksum = cqi->new_sha1_checksum;
 
16398
 
 
16399
          /* Recurse.  Pass NULL for NEW_DAV_CACHE, because the
 
16400
             ones present in the current call are only applicable to
 
16401
             this one committed item. */
 
16402
          SVN_ERR(process_committed_internal(
 
16403
                    db, wcroot, this_relpath,
 
16404
                    TRUE /* recurse */,
 
16405
                    FALSE /* top_of_recurse */,
 
16406
                    new_revnum, new_date,
 
16407
                    rev_author,
 
16408
                    NULL /* new_dav_cache */,
 
16409
                    FALSE /* remove_lock */,
 
16410
                    remove_changelist,
 
16411
                    new_sha1_checksum,
 
16412
                    items_by_relpath,
 
16413
                    iterpool));
 
16414
        }
 
16415
 
 
16416
      svn_pool_destroy(iterpool);
 
16417
    }
 
16418
 
 
16419
  return SVN_NO_ERROR;
 
16420
}
 
16421
 
 
16422
/* Return TRUE if any item of QUEUE is a parent of ITEM and will be
 
16423
   processed recursively, return FALSE otherwise.
 
16424
 
 
16425
   The algorithmic complexity of this search implementation is O(queue
 
16426
   length), but it's quite quick.
 
16427
*/
 
16428
static svn_boolean_t
 
16429
have_recursive_parent(const apr_array_header_t *all_items,
 
16430
                      const commit_queue_item_t *item,
 
16431
                      apr_pool_t *scratch_pool)
 
16432
{
 
16433
  const char *local_relpath = item->local_relpath;
 
16434
  int i;
 
16435
 
 
16436
  for (i = 0; i < all_items->nelts; i++)
 
16437
    {
 
16438
      const commit_queue_item_t *qi
 
16439
        = APR_ARRAY_IDX(all_items, i, const commit_queue_item_t *);
 
16440
 
 
16441
      if (qi == item)
 
16442
        continue;
 
16443
 
 
16444
      if (qi->recurse && svn_relpath_skip_ancestor(qi->local_relpath,
 
16445
                                                   local_relpath))
 
16446
        {
 
16447
          return TRUE;
 
16448
        }
 
16449
    }
 
16450
 
 
16451
  return FALSE;
 
16452
}
 
16453
 
 
16454
/* Compare function for svn_sort__array */
 
16455
static int
 
16456
compare_queue_items(const void *v1,
 
16457
                    const void *v2)
 
16458
{
 
16459
  const commit_queue_item_t *cqi1
 
16460
              = *(const commit_queue_item_t **)v1;
 
16461
  const commit_queue_item_t *cqi2
 
16462
              = *(const commit_queue_item_t **)v2;
 
16463
 
 
16464
  return svn_path_compare_paths(cqi1->local_relpath, cqi2->local_relpath);
 
16465
}
 
16466
 
 
16467
/* Internal, locked version of svn_wc__db_process_commit_queue */
 
16468
static svn_error_t *
 
16469
db_process_commit_queue(svn_wc__db_t *db,
 
16470
                        svn_wc__db_commit_queue_t *queue,
 
16471
                        svn_revnum_t new_revnum,
 
16472
                        apr_time_t new_date,
 
16473
                        const char *new_author,
 
16474
                        apr_pool_t *scratch_pool)
 
16475
{
 
16476
  apr_hash_t *items_by_relpath = NULL;
 
16477
  int j;
 
16478
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
16479
 
 
16480
  svn_sort__array(queue->items, compare_queue_items);
 
16481
 
 
16482
  if (queue->have_recurse)
 
16483
    {
 
16484
      items_by_relpath = apr_hash_make(scratch_pool);
 
16485
 
 
16486
      for (j = 0; j < queue->items->nelts; j++)
 
16487
        {
 
16488
          commit_queue_item_t *cqi
 
16489
            = APR_ARRAY_IDX(queue->items, j, commit_queue_item_t *);
 
16490
 
 
16491
          svn_hash_sets(items_by_relpath, cqi->local_relpath, cqi);
 
16492
        }
 
16493
    }
 
16494
 
 
16495
  for (j = 0; j < queue->items->nelts; j++)
 
16496
    {
 
16497
      commit_queue_item_t *cqi
 
16498
        = APR_ARRAY_IDX(queue->items, j, commit_queue_item_t *);
 
16499
 
 
16500
      svn_pool_clear(iterpool);
 
16501
 
 
16502
      /* Skip this item if it is a child of a recursive item, because it has
 
16503
         been (or will be) accounted for when that recursive item was (or
 
16504
         will be) processed. */
 
16505
      if (queue->have_recurse && have_recursive_parent(queue->items, cqi,
 
16506
                                                       iterpool))
 
16507
        continue;
 
16508
 
 
16509
      if (!cqi->committed)
 
16510
        {
 
16511
          if (cqi->remove_lock)
 
16512
            {
 
16513
              svn_skel_t *work_item;
 
16514
 
 
16515
              SVN_ERR(svn_wc__wq_build_sync_file_flags(
 
16516
                                                    &work_item,
 
16517
                                                    db,
 
16518
                                                    svn_dirent_join(
 
16519
                                                        queue->wcroot->abspath,
 
16520
                                                        cqi->local_relpath,
 
16521
                                                        iterpool),
 
16522
                                                    iterpool, iterpool));
 
16523
 
 
16524
              lock_remove_txn(queue->wcroot, cqi->local_relpath, work_item,
 
16525
                              iterpool);
 
16526
            }
 
16527
          if (cqi->remove_changelist)
 
16528
            SVN_ERR(svn_wc__db_op_set_changelist(db,
 
16529
                                                 svn_dirent_join(
 
16530
                                                        queue->wcroot->abspath,
 
16531
                                                        cqi->local_relpath,
 
16532
                                                        iterpool),
 
16533
                                                 NULL, NULL,
 
16534
                                                 svn_depth_empty,
 
16535
                                                 NULL, NULL, /* notify */
 
16536
                                                 NULL, NULL, /* cancel */
 
16537
                                                 iterpool));
 
16538
        }
 
16539
      else
 
16540
        {
 
16541
          SVN_ERR(process_committed_internal(
 
16542
                                  db, queue->wcroot, cqi->local_relpath,
 
16543
                                  cqi->recurse,
 
16544
                                  TRUE /* top_of_recurse */,
 
16545
                                  new_revnum, new_date, new_author,
 
16546
                                  cqi->new_dav_cache,
 
16547
                                  cqi->remove_lock,
 
16548
                                  cqi->remove_changelist,
 
16549
                                  cqi->new_sha1_checksum,
 
16550
                                  items_by_relpath,
 
16551
                                  iterpool));
 
16552
        }
 
16553
    }
 
16554
 
 
16555
  svn_pool_destroy(iterpool);
 
16556
 
 
16557
  return SVN_NO_ERROR;
 
16558
}
 
16559
 
 
16560
svn_error_t *
 
16561
svn_wc__db_process_commit_queue(svn_wc__db_t *db,
 
16562
                                svn_wc__db_commit_queue_t *queue,
 
16563
                                svn_revnum_t new_revnum,
 
16564
                                apr_time_t new_date,
 
16565
                                const char *new_author,
 
16566
                                apr_pool_t *scratch_pool)
 
16567
{
 
16568
  SVN_WC__DB_WITH_TXN(db_process_commit_queue(db, queue,
 
16569
                                              new_revnum, new_date,
 
16570
                                              new_author, scratch_pool),
 
16571
                        queue->wcroot);
 
16572
 
 
16573
  return SVN_NO_ERROR;
 
16574
}