Prechádzať zdrojové kódy

Merge pull request #11607 from AttilaVamos/HPCC-19489-improvement-7.2.0

HPCC-19489 STD.File.RenameLogicalFile should support OVERWRITE

Reviewed-By: Jake Smith <jake.smith@lexisnexis.com>
Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 6 rokov pred
rodič
commit
7c1df8268b

+ 3 - 2
ecllibrary/std/File.ecl

@@ -134,10 +134,11 @@ EXPORT SetReadOnly(varstring lfn, boolean ro=TRUE) :=
  *
  * @param oldname       The current name of the file to be renamed.
  * @param newname       The new logical name of the file.
+ * @param allowOverwrite Is it valid to overwrite an existing file of the same name?  Defaults to FALSE
  */
 
-EXPORT RenameLogicalFile(varstring oldname, varstring newname) :=
-    lib_fileservices.FileServices.RenameLogicalFile(oldname, newname);
+EXPORT RenameLogicalFile(varstring oldname, varstring newname, boolean allowOverwrite=FALSE) :=
+    lib_fileservices.FileServices.RenameLogicalFile(oldname, newname, allowOverwrite);
 
 /**
  * Returns a logical filename that can be used to refer to a logical file in a local or remote dali.

+ 28 - 11
plugins/fileservices/fileservices.cpp

@@ -64,7 +64,7 @@ static const char * EclDefinition =
 "  boolean FileExists(const varstring lfn, boolean physical=false) : c,context,entrypoint='fsFileExists'; \n"
 "  DeleteLogicalFile(const varstring lfn,boolean ifexists=false) : c,action,context,entrypoint='fsDeleteLogicalFile'; \n"
 "  SetReadOnly(const varstring lfn, boolean ro) : c,action,context,entrypoint='fsSetReadOnly'; \n"
-"  RenameLogicalFile(const varstring oldname, const varstring newname) : c,action,context,entrypoint='fsRenameLogicalFile'; \n"
+"  RenameLogicalFile(const varstring oldname, const varstring newname, boolean allowoverwrite=false) : c,action,context,entrypoint='fsRenameLogicalFile_v2'; \n"
 "  varstring GetBuildInfo() : c,pure,entrypoint='fsGetBuildInfo';\n"
 "  SendEmail(const varstring to, const varstring subject, const varstring body, const varstring mailServer=GETENV('SMTPserver'), unsigned4 port=(unsigned4) GETENV('SMTPport', '25'), const varstring sender=GETENV('emailSenderAddress')) : c,action,context,entrypoint='fsSendEmail'; \n"
 "  SendEmailAttachText(const varstring to, const varstring subject, const varstring body, const varstring attachment, const varstring mimeType, const varstring attachmentName, const varstring mailServer=GETENV('SMTPserver'), unsigned4 port=(unsigned4) GETENV('SMTPport', '25'), const varstring sender=GETENV('emailSenderAddress')) : c,action,context,entrypoint='fsSendEmailAttachText'; \n"
@@ -523,31 +523,48 @@ FILESERVICES_API void FILESERVICES_CALL fsSetReadOnly(ICodeContext *ctx, const c
     throw error.getClear();
 }
 
-
-FILESERVICES_API void FILESERVICES_CALL fsRenameLogicalFile(ICodeContext *ctx, const char *oldname, const char *newname)
+FILESERVICES_API void FILESERVICES_CALL implementRenameLogicalFile(ICodeContext *ctx, const char *oldname, const char *newname, const bool overwrite)
 {
-    StringBuffer lfn, nlfn;
-    constructLogicalName(ctx, oldname, lfn);
-    constructLogicalName(ctx, newname, nlfn);
+    StringBuffer oldLfn, newLfn;
+    constructLogicalName(ctx, oldname, oldLfn);
+    constructLogicalName(ctx, newname, newLfn);
 
     IDistributedFileTransaction *transaction = ctx->querySuperFileTransaction();
     Linked<IUserDescriptor> udesc = ctx->queryUserDescriptor();
+    IDistributedFileDirectory &distributedDirectory = queryDistributedFileDirectory();
+
+    if (!distributedDirectory.exists(oldLfn.str(), udesc, false, false))
+        throw MakeStringException(0, "Old file %s doesn't exists.", oldLfn.str());
+
+    if (overwrite && distributedDirectory.exists(newLfn.str(), udesc, false, false))
+        fsDeleteLogicalFile(ctx, newname, true);
+
     try {
-        queryDistributedFileDirectory().renamePhysical(lfn.str(),nlfn.str(),udesc,transaction);
+        distributedDirectory.renamePhysical(oldLfn.str(), newLfn.str(), udesc, transaction);
         StringBuffer s("RenameLogicalFile ('");
-        s.append(lfn).append(", '").append(nlfn).append("') done");
-        WUmessage(ctx,SeverityInformation,NULL,s.str());
-        AuditMessage(ctx,"RenameLogicalFile",lfn.str(),nlfn.str());
+        s.append(oldLfn).append(", '").append(newLfn).append("') done");
+        WUmessage(ctx, SeverityInformation, NULL, s.str());
+        AuditMessage(ctx, "RenameLogicalFile", oldLfn.str(), newLfn.str());
     }
     catch (IException *e)
     {
         StringBuffer s;
         e->errorMessage(s);
-        WUmessage(ctx,SeverityWarning,"RenameLogicalFile",s.str());
+        WUmessage(ctx, SeverityWarning, "RenameLogicalFile", s.str());
         throw e;
      }
 }
 
+FILESERVICES_API void FILESERVICES_CALL fsRenameLogicalFile(ICodeContext *ctx, const char *oldname, const char *newname)
+{
+    implementRenameLogicalFile(ctx, oldname, newname, false);
+}
+
+FILESERVICES_API void FILESERVICES_CALL fsRenameLogicalFile_v2(ICodeContext *ctx, const char *oldname, const char *newname, const bool overwrite)
+{
+    implementRenameLogicalFile(ctx, oldname, newname, overwrite);
+}
+
 
 FILESERVICES_API void FILESERVICES_CALL fsSendEmail(ICodeContext * ctx, const char * to, const char * subject, const char * body, const char * mailServer, unsigned port, const char * sender)
 {

+ 1 - 0
plugins/fileservices/fileservices.hpp

@@ -45,6 +45,7 @@ FILESERVICES_API void FILESERVICES_CALL fsDeleteLogicalFile(ICodeContext *ctx, c
 FILESERVICES_API bool FILESERVICES_CALL fsFileValidate(ICodeContext *ctx, const char *name);
 FILESERVICES_API void FILESERVICES_CALL fsSetReadOnly(ICodeContext *ctx, const char *name, bool ro);
 FILESERVICES_API void FILESERVICES_CALL fsRenameLogicalFile(ICodeContext *ctx, const char *oldname, const char *newname);
+FILESERVICES_API void FILESERVICES_CALL fsRenameLogicalFile_v2(ICodeContext *ctx, const char *oldname, const char *newname, bool overwrite=false);
 FILESERVICES_API void FILESERVICES_CALL fsSendEmail(ICodeContext * ctx, const char *to, const char * subject, const char * body, const char * mailServer, unsigned port, const char * sender);
 FILESERVICES_API void FILESERVICES_CALL fsSendEmailAttachText(ICodeContext * ctx, const char * to, const char * subject, const char * body, const char * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender);
 FILESERVICES_API void FILESERVICES_CALL fsSendEmailAttachData(ICodeContext * ctx, const char * to, const char * subject, const char * body, size32_t lenAttachment, const void * attachment, const char * mimeType, const char * attachmentName, const char * mailServer, unsigned int port, const char * sender);

+ 14 - 1
testing/regress/ecl/fileservice.ecl

@@ -26,6 +26,13 @@ rec := RECORD
 END;
 
 ds := DATASET([{'fruit', 123, 'apple'}, {'fruit', 246, 'ford'}, {'os', 680, 'bsd'}, {'music', 369, 'rhead'}, {'os', 987, 'os'}], rec);
+ds2 := DATASET( prefix + 'afterrename1.d00', rec, flat);
+
+string compareDatasets(dataset(rec) ds1, dataset(rec) ds2) := FUNCTION
+   boolean result := (0 = COUNT(JOIN(ds1, ds2, left.name=right.name, FULL ONLY)));
+   RETURN if(result, 'Pass', 'Fail');
+END;
+
 
 SEQUENTIAL(
   OUTPUT(ds, , prefix + 'renametest.d00', OVERWRITE),
@@ -33,5 +40,11 @@ SEQUENTIAL(
   File.RenameLogicalFile(prefix + 'afterrename1.d00', prefix + 'scope1::scope2::afterrename2.d00'),
   File.RenameLogicalFile(prefix + 'scope1::scope2::afterrename2.d00', prefix + 'scope1::afterrename3.d00'),
   OUTPUT(DATASET(prefix + 'scope1::afterrename3.d00', rec, FLAT)),
-  File.DeleteLogicalFile(prefix + 'scope1::afterrename3.d00')
+  File.DeleteLogicalFile(prefix + 'scope1::afterrename3.d00'),
+  OUTPUT(ds, , prefix + 'renametest.d00', OVERWRITE),
+  OUTPUT(ds, , prefix + 'afterrename1.d00', OVERWRITE),
+  // Rename with overwrite allowed
+  File.RenameLogicalFile(prefix + 'renametest.d00', prefix + 'afterrename1.d00', true),
+  output(compareDatasets(ds, ds2)),
+  File.DeleteLogicalFile(prefix + 'afterrename1.d00'),
 );

+ 7 - 0
testing/regress/ecl/key/fileservice.xml

@@ -7,3 +7,10 @@
  <Row><name>music </name><blah>369</blah><value>rhead    </value></Row>
  <Row><name>os    </name><blah>987</blah><value>os       </value></Row>
 </Dataset>
+<Dataset name='Result 3'>
+</Dataset>
+<Dataset name='Result 4'>
+</Dataset>
+<Dataset name='Result 5'>
+ <Row><Result_5>Pass</Result_5></Row>
+</Dataset>