SOURCES: bacula-2.2.4-ansi-label.patch (NEW), bacula-2.2.4-lost-bl...
areq
areq at pld-linux.org
Wed Oct 10 15:41:26 CEST 2007
Author: areq Date: Wed Oct 10 13:41:26 2007 GMT
Module: SOURCES Tag: HEAD
---- Log message:
- official patches
---- Files affected:
SOURCES:
bacula-2.2.4-ansi-label.patch (NONE -> 1.1) (NEW), bacula-2.2.4-lost-block.patch (NONE -> 1.1) (NEW), bacula-2.2.4-parse-command.patch (NONE -> 1.1) (NEW), bacula-2.2.4-poll-mount.patch (NONE -> 1.1) (NEW), bacula-2.2.4-replace.patch (NONE -> 1.1) (NEW), bacula-2.2.4-restore.patch (NONE -> 1.1) (NEW), bacula-2.2.4-sd-auth-fail.patch (NONE -> 1.1) (NEW), bacula-2.2.4-sql.patch (NONE -> 1.1) (NEW), bacula-2.2.4-verify.patch (NONE -> 1.1) (NEW)
---- Diffs:
================================================================
Index: SOURCES/bacula-2.2.4-ansi-label.patch
diff -u /dev/null SOURCES/bacula-2.2.4-ansi-label.patch:1.1
--- /dev/null Wed Oct 10 15:41:26 2007
+++ SOURCES/bacula-2.2.4-ansi-label.patch Wed Oct 10 15:41:21 2007
@@ -0,0 +1,77 @@
+
+ This patch fixes bug #954.
+ WEOF on non-appendable error when trying to label a tape with ANSI labels turned on.
+
+ Apply it to version 2.2.4 (possibly earlier versions with):
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-verify.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+Index: block.c
+===================================================================
+--- src/stored/block.c (revision 5615)
++++ src/stored/block.c (revision 5615)
+@@ -273,6 +273,7 @@
+ dev->dev_errno = EIO;
+ Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"),
+ dev->file, dev->block_num, BLKHDR2_ID, Id);
++ Dmsg1(50, "%s", dev->errmsg);
+ if (block->read_errors == 0 || verbose >= 2) {
+ Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+ }
+@@ -1008,8 +1009,19 @@
+ dev->set_ateof();
+ return false; /* return eof */
+ }
++
+ /* Continue here for successful read */
++
+ block->read_len = stat; /* save length read */
++ if (dev->at_eof() && block->read_len == 80 &&
++ (dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
++ dcr->device->label_type != B_BACULA_LABEL)) {
++ /* ***FIXME*** should check label */
++ Dmsg2(100, "Ignore 80 byte ANSI label at %u:%u\n", dev->file, dev->block_num);
++ dev->clear_eof();
++ goto reread; /* skip ANSI/IBM label */
++ }
++
+ if (block->read_len < BLKHDR2_LENGTH) {
+ dev->dev_errno = EIO;
+ Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Very short block of %d bytes on device %s discarded.\n"),
+
+Index: label.c
+===================================================================
+--- src/stored/label.c (revision 5602)
++++ src/stored/label.c (working copy)
+@@ -119,7 +119,6 @@
+ bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
+
+ /* Read ANSI/IBM label if so requested */
+-
+ want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
+ dcr->device->label_type != B_BACULA_LABEL;
+ if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
+@@ -344,6 +343,9 @@
+ }
+ }
+
++ /* Temporarily mark in append state to enable writing */
++ dev->set_append();
++
+ /* Create PRE_LABEL or VOL_LABEL if DVD */
+ create_volume_label(dev, VolName, PoolName, dvdnow);
+
+@@ -364,8 +366,6 @@
+ create_volume_label_record(dcr, dcr->rec);
+ dcr->rec->Stream = 0;
+
+- /* Temporarily mark in append state to enable writing */
+- dev->set_append();
+ if (!write_record_to_block(dcr->block, dcr->rec)) {
+ Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
+ goto bail_out;
================================================================
Index: SOURCES/bacula-2.2.4-lost-block.patch
diff -u /dev/null SOURCES/bacula-2.2.4-lost-block.patch:1.1
--- /dev/null Wed Oct 10 15:41:26 2007
+++ SOURCES/bacula-2.2.4-lost-block.patch Wed Oct 10 15:41:21 2007
@@ -0,0 +1,30 @@
+
+ This patch fixes a race condition where a Job is terminating at the same
+ time that another job reaches the end of Volume. In that case, sometimes
+ the last block or two are not written to the Volume. This seems to be
+ relatively rare, but does result in data loss. This fixes bug #964.
+
+ Apply the patch to Bacula version 2.2.4 (or possibly any previous 2.2.x
+ version) with:
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-lost-block.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+Index: src/stored/append.c
+===================================================================
+--- src/stored/append.c (revision 5602)
++++ src/stored/append.c (working copy)
+@@ -287,7 +287,7 @@
+ * Check if we can still write. This may not be the case
+ * if we are at the end of the tape or we got a fatal I/O error.
+ */
+- if (dev->can_write()) {
++ if (ok || dev->can_write()) {
+ if (!write_session_label(dcr, EOS_LABEL)) {
+ Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"),
+ dev->bstrerror());
================================================================
Index: SOURCES/bacula-2.2.4-parse-command.patch
diff -u /dev/null SOURCES/bacula-2.2.4-parse-command.patch:1.1
--- /dev/null Wed Oct 10 15:41:26 2007
+++ SOURCES/bacula-2.2.4-parse-command.patch Wed Oct 10 15:41:21 2007
@@ -0,0 +1,28 @@
+
+ This patch resolves a command parser issue
+ causing a director segfault when using something
+ like "run job 1 2"
+
+ Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-parse-command.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+Index: src/dird/ua_run.c
+===================================================================
+--- src/dird/ua_run.c (révision 5616)
++++ src/dird/ua_run.c (copie de travail)
+@@ -933,7 +933,7 @@
+ /* Note, yes and run have no value, so do not fail */
+ if (!ua->argv[i] && j != YES_POS /*yes*/) {
+ ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
+- return true;
++ return false;
+ }
+ Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
+ switch (j) {
================================================================
Index: SOURCES/bacula-2.2.4-poll-mount.patch
diff -u /dev/null SOURCES/bacula-2.2.4-poll-mount.patch:1.1
--- /dev/null Wed Oct 10 15:41:26 2007
+++ SOURCES/bacula-2.2.4-poll-mount.patch Wed Oct 10 15:41:21 2007
@@ -0,0 +1,27 @@
+
+ This patch resolves bug #908 where a tape is not properly mounted
+ (recognized) during a poll.
+
+ Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-poll-mount.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+Index: src/stored/dev.c
+===================================================================
+--- src/stored/dev.c (revision 5553)
++++ src/stored/dev.c (working copy)
+@@ -1844,7 +1844,8 @@
+
+ /* Clean up device packet so it can be reused */
+ clear_opened();
+- state &= ~(ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF);
++ state &= ~(ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF|
++ ST_MOUNTED|ST_MEDIA|ST_SHORT|ST_FREESPACE_OK|ST_PART_SPOOLED);
+ label_type = B_BACULA_LABEL;
+ file = block_num = 0;
+ file_size = 0;
================================================================
Index: SOURCES/bacula-2.2.4-replace.patch
diff -u /dev/null SOURCES/bacula-2.2.4-replace.patch:1.1
--- /dev/null Wed Oct 10 15:41:26 2007
+++ SOURCES/bacula-2.2.4-replace.patch Wed Oct 10 15:41:21 2007
@@ -0,0 +1,24 @@
+
+ This patch resolves bug #969 where the user can't change the
+ replace option in the restore menu
+
+ Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-replace.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+--- src/dird/ua_run.c (révision 5721)
++++ src/dird/ua_run.c (copie de travail)
+@@ -424,6 +424,7 @@
+ }
+ opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
+ if (opt >= 0) {
++ rc.replace = ReplaceOptions[opt].name;
+ jcr->replace = ReplaceOptions[opt].token;
+ }
+ goto try_again;
+
================================================================
Index: SOURCES/bacula-2.2.4-restore.patch
diff -u /dev/null SOURCES/bacula-2.2.4-restore.patch:1.1
--- /dev/null Wed Oct 10 15:41:26 2007
+++ SOURCES/bacula-2.2.4-restore.patch Wed Oct 10 15:41:21 2007
@@ -0,0 +1,49 @@
+
+ This patch resolves bug #955 where the director segfault when
+ where= option isn't specified anywhere.
+
+ Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-restore.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+Index: src/dird/restore.c
+===================================================================
+--- src/dird/restore.c (revision 5601)
++++ src/dird/restore.c (working copy)
+@@ -173,7 +173,7 @@
+ }
+
+ /* Send restore command */
+- char replace, *where, *cmd=NULL;
++ char replace, *where, *cmd;
+ char empty = '\0';
+
+ if (jcr->replace != 0) {
+@@ -183,8 +183,6 @@
+ } else {
+ replace = REPLACE_ALWAYS; /* always replace */
+ }
+-
+- where = ∅ /* default */
+
+ if (jcr->RegexWhere) {
+ where = jcr->RegexWhere; /* override */
+@@ -199,7 +197,11 @@
+ } else if (jcr->job->RestoreWhere) {
+ where = jcr->job->RestoreWhere; /* no override take from job */
+ cmd = restorecmd;
+- }
++
++ } else { /* nothing was specified */
++ where = ∅ /* use default */
++ cmd = restorecmd;
++ }
+
+ jcr->prefix_links = jcr->job->PrefixLinks;
+
================================================================
Index: SOURCES/bacula-2.2.4-sd-auth-fail.patch
diff -u /dev/null SOURCES/bacula-2.2.4-sd-auth-fail.patch:1.1
--- /dev/null Wed Oct 10 15:41:26 2007
+++ SOURCES/bacula-2.2.4-sd-auth-fail.patch Wed Oct 10 15:41:21 2007
@@ -0,0 +1,159 @@
+
+ This patch applies to Bacula version 2.2.4 (possibly earlier 2.2.x versions)
+ and fixes a Storage daemon authentication problem with the FD. This fixes
+ bug #953. The patch also adds a bit of additional debug code and significantly
+ strengthens the SD session key.
+
+ Apply it to 2.2.4 with:
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-sd-auth-fail.patch
+ make
+ ...
+ make install
+
+
+Index: src/stored/job.c
+===================================================================
+--- src/stored/job.c (revision 5602)
++++ src/stored/job.c (working copy)
+@@ -73,6 +73,7 @@
+ {
+ int JobId;
+ char auth_key[100];
++ char seed[100];
+ BSOCK *dir = jcr->dir_bsock;
+ POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
+ int JobType, level, spool_attributes, no_attributes, spool_data;
+@@ -91,7 +92,7 @@
+ &write_part_after_job, &PreferMountedVols);
+ if (stat != 13) {
+ pm_strcpy(jcr->errmsg, dir->msg);
+- bnet_fsend(dir, BAD_job, stat, jcr->errmsg);
++ dir->fsend(BAD_job, stat, jcr->errmsg);
+ Dmsg1(100, ">dird: %s", dir->msg);
+ set_jcr_job_status(jcr, JS_ErrorTerminated);
+ return false;
+@@ -134,9 +135,10 @@
+ /*
+ * Pass back an authorization key for the File daemon
+ */
+- make_session_key(auth_key, NULL, 1);
+- bnet_fsend(dir, OKjob, jcr->VolSessionId, jcr->VolSessionTime, auth_key);
+- Dmsg1(100, ">dird: %s", dir->msg);
++ bsnprintf(seed, sizeof(seed), "%p%d", jcr, JobId);
++ make_session_key(auth_key, seed, 1);
++ dir->fsend(OKjob, jcr->VolSessionId, jcr->VolSessionTime, auth_key);
++ Dmsg2(100, ">dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
+ jcr->sd_auth_key = bstrdup(auth_key);
+ memset(auth_key, 0, sizeof(auth_key));
+ generate_daemon_event(jcr, "JobStart");
+@@ -169,17 +171,18 @@
+ timeout.tv_nsec = tv.tv_usec * 1000;
+ timeout.tv_sec = tv.tv_sec + me->client_wait;
+
+- Dmsg2(100, "%s waiting %d sec for FD to contact SD\n",
+- jcr->Job, (int)me->client_wait);
++ Dmsg3(050, "%s waiting %d sec for FD to contact SD key=%s\n",
++ jcr->Job, (int)me->client_wait, jcr->sd_auth_key);
++
+ /*
+ * Wait for the File daemon to contact us to start the Job,
+ * when he does, we will be released, unless the 30 minutes
+ * expires.
+ */
+ P(mutex);
+- for ( ; !job_canceled(jcr); ) {
++ while ( !jcr->authenticated && !job_canceled(jcr) ) {
+ errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
+- if (errstat == 0 || errstat == ETIMEDOUT) {
++ if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
+ break;
+ }
+ }
+@@ -195,7 +198,7 @@
+ }
+
+ /*
+- * After receiving a connection (in job.c) if it is
++ * After receiving a connection (in dircmd.c) if it is
+ * from the File daemon, this routine is called.
+ */
+ void handle_filed_connection(BSOCK *fd, char *job_name)
+@@ -204,8 +207,8 @@
+
+ bmicrosleep(0, 50000); /* wait 50 millisecs */
+ if (!(jcr=get_jcr_by_full_name(job_name))) {
+- Jmsg1(NULL, M_FATAL, 0, _("Job name not found: %s\n"), job_name);
+- Dmsg1(100, "Job name not found: %s\n", job_name);
++ Jmsg1(NULL, M_FATAL, 0, _("FD connect failed: Job name not found: %s\n"), job_name);
++ Dmsg1(3, "**** Job \"%s\" not found", job_name);
+ return;
+ }
+
+@@ -216,7 +219,7 @@
+
+ if (jcr->authenticated) {
+ Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"),
+- jcr->JobId, jcr->Job);
++ (uint32_t)jcr->JobId, jcr->Job);
+ free_jcr(jcr);
+ return;
+ }
+@@ -229,7 +232,7 @@
+ Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
+ } else {
+ jcr->authenticated = true;
+- Dmsg1(110, "OK Authentication Job %s\n", jcr->Job);
++ Dmsg2(110, "OK Authentication jid=%u Job %s\n", (uint32_t)jcr->JobId, jcr->Job);
+ }
+
+ if (!jcr->authenticated) {
+@@ -274,9 +277,9 @@
+ }
+ ok = dir_update_device(jcr, device->dev);
+ if (ok) {
+- ok = bnet_fsend(dir, OK_query);
++ ok = dir->fsend(OK_query);
+ } else {
+- bnet_fsend(dir, NO_query);
++ dir->fsend(NO_query);
+ }
+ return ok;
+ }
+@@ -289,9 +292,9 @@
+ }
+ ok = dir_update_changer(jcr, changer);
+ if (ok) {
+- ok = bnet_fsend(dir, OK_query);
++ ok = dir->fsend(OK_query);
+ } else {
+- bnet_fsend(dir, NO_query);
++ dir->fsend(NO_query);
+ }
+ return ok;
+ }
+@@ -299,12 +302,12 @@
+ /* If we get here, the device/autochanger was not found */
+ unbash_spaces(dir->msg);
+ pm_strcpy(jcr->errmsg, dir->msg);
+- bnet_fsend(dir, NO_device, dev_name.c_str());
++ dir->fsend(NO_device, dev_name.c_str());
+ Dmsg1(100, ">dird: %s\n", dir->msg);
+ } else {
+ unbash_spaces(dir->msg);
+ pm_strcpy(jcr->errmsg, dir->msg);
+- bnet_fsend(dir, BAD_query, jcr->errmsg);
++ dir->fsend(BAD_query, jcr->errmsg);
+ Dmsg1(100, ">dird: %s\n", dir->msg);
+ }
+
+@@ -322,7 +325,7 @@
+ {
+ Dmsg1(900, "stored_free_jcr JobId=%u\n", jcr->JobId);
+ if (jcr->file_bsock) {
+- bnet_close(jcr->file_bsock);
++ jcr->file_bsock->close();
+ jcr->file_bsock = NULL;
+ }
+ if (jcr->job_name) {
================================================================
Index: SOURCES/bacula-2.2.4-sql.patch
diff -u /dev/null SOURCES/bacula-2.2.4-sql.patch:1.1
--- /dev/null Wed Oct 10 15:41:26 2007
+++ SOURCES/bacula-2.2.4-sql.patch Wed Oct 10 15:41:21 2007
@@ -0,0 +1,476 @@
+
+ This patch fixes several problems: it fixes incorrect or incomplete error
+ messages; it fixes a problem opening the SQLite3 database when multiple
+ simultaneous jobs were running; it fixes a bug with certain versions of
+ MySQL where batch inserts failed because of table name character case
+ (upper/lower) differences.
+
+ It can be applied to version 2.2.4 (and possibly earlier 2.2.x versions)
+ with:
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-sql.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+
+Index: src/cats/sql.c
+===================================================================
+--- src/cats/sql.c (revision 5687)
++++ src/cats/sql.c (working copy)
+@@ -115,7 +115,6 @@
+
+ bacula_db_version = 0;
+ if (!db_sql_query(mdb, query, int_handler, (void *)&bacula_db_version)) {
+- Mmsg(mdb->errmsg, "Database not created or server not running.\n");
+ Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
+ return false;
+ }
+Index: src/cats/sqlite.c
+===================================================================
+--- src/cats/sqlite.c (revision 5687)
++++ src/cats/sqlite.c (working copy)
+@@ -148,6 +148,7 @@
+ int len;
+ struct stat statbuf;
+ int errstat;
++ int retry = 0;
+
+ P(mutex);
+ if (mdb->connected) {
+@@ -157,8 +158,9 @@
+ mdb->connected = FALSE;
+
+ if ((errstat=rwl_init(&mdb->lock)) != 0) {
++ berrno be;
+ Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
+- strerror(errstat));
++ be.bstrerror(errstat));
+ V(mutex);
+ return 0;
+ }
+@@ -178,28 +180,28 @@
+ return 0;
+ }
+
++ for (mdb->db=NULL; !mdb->db && retry++ < 10; ) {
+ #ifdef HAVE_SQLITE3
+- int stat = sqlite3_open(db_name, &mdb->db);
+- if (stat != SQLITE_OK) {
+- mdb->sqlite_errmsg = (char *)sqlite3_errmsg(mdb->db);
+- sqlite3_close(mdb->db);
+- mdb->db = NULL;
+- } else {
+- mdb->sqlite_errmsg = NULL;
+- }
+-#ifdef SQLITE3_INIT_QUERY
+- db_sql_query(mdb, SQLITE3_INIT_QUERY, NULL, NULL);
+-#endif
+-
++ int stat = sqlite3_open(db_name, &mdb->db);
++ if (stat != SQLITE_OK) {
++ mdb->sqlite_errmsg = (char *)sqlite3_errmsg(mdb->db);
++ sqlite3_close(mdb->db);
++ mdb->db = NULL;
++ } else {
++ mdb->sqlite_errmsg = NULL;
++ }
+ #else
+- mdb->db = sqlite_open(
+- db_name, /* database name */
+- 644, /* mode */
+- &mdb->sqlite_errmsg); /* error message */
++ mdb->db = sqlite_open(
++ db_name, /* database name */
++ 644, /* mode */
++ &mdb->sqlite_errmsg); /* error message */
+ #endif
+
+- Dmsg0(300, "sqlite_open\n");
+-
++ Dmsg0(300, "sqlite_open\n");
++ if (!mdb->db) {
++ bmicrosleep(1, 0);
++ }
++ }
+ if (mdb->db == NULL) {
+ Mmsg2(&mdb->errmsg, _("Unable to open Database=%s. ERR=%s\n"),
+ db_name, mdb->sqlite_errmsg ? mdb->sqlite_errmsg : _("unknown"));
+@@ -209,10 +211,6 @@
+ }
+ mdb->connected = true;
+ free(db_name);
+- if (!check_tables_version(jcr, mdb)) {
+- V(mutex);
+- return 0;
+- }
+
+ /* set busy handler to wait when we use mult_db_connections = 1 */
+ #ifdef HAVE_SQLITE3
+@@ -221,6 +219,16 @@
+ sqlite_busy_handler(mdb->db, my_busy_handler, NULL);
+ #endif
+
++#if defined(HAVE_SQLITE3) && defined(SQLITE3_INIT_QUERY)
++ db_sql_query(mdb, SQLITE3_INIT_QUERY, NULL, NULL);
++#endif
++
++ if (!check_tables_version(jcr, mdb)) {
++ V(mutex);
++ return 0;
++ }
++
++
+ V(mutex);
+ return 1;
+ }
+@@ -448,16 +456,20 @@
+ return mdb->fields[mdb->field++];
+ }
+
+-char *my_sqlite_batch_lock_query = "BEGIN";
+-char *my_sqlite_batch_unlock_query = "COMMIT";
+-char *my_sqlite_batch_fill_path_query = "INSERT INTO Path (Path) "
+- " SELECT DISTINCT Path FROM batch "
+- " EXCEPT SELECT Path FROM Path ";
++#ifdef HAVE_BATCH_FILE_INSERT
++const char *my_sqlite_batch_lock_query = "BEGIN";
++const char *my_sqlite_batch_unlock_query = "COMMIT";
+
+-char *my_sqlite_batch_fill_filename_query = "INSERT INTO Filename (Name) "
+- " SELECT DISTINCT Name FROM batch "
+- " EXCEPT SELECT Name FROM Filename ";
++const char *my_sqlite_batch_fill_path_query =
++ "INSERT INTO Path (Path)"
++ " SELECT DISTINCT Path FROM batch"
++ " EXCEPT SELECT Path FROM Path";
+
++const char *my_sqlite_batch_fill_filename_query =
++ "INSERT INTO Filename (Name)"
++ " SELECT DISTINCT Name FROM batch "
++ " EXCEPT SELECT Name FROM Filename";
++#endif /* HAVE_BATCH_FILE_INSERT */
<<Diff was trimmed, longer than 597 lines>>
More information about the pld-cvs-commit
mailing list