I have an ANT script that I use to deploy PostgreSQL schema. As part of the
script I load data into the database using PostgreSQL's COPY statement.
On Unix (both Mac OS X and Linux), I do the following:
<tpsqlcmd cmd="COPY Planet FROM STDIN WITH CSV DELIMITER AS ','
QUOTE AS '"' ESCAPE AS '"'"
input="${dist.db.data}${file.separator}Planet.csv"/>
where tpsqlcmd is a macro I wrote that looks like this:
<!-- macro for invoking a PostgreSQL command with terse output -->
<macrodef name="tpsqlcmd">
<attribute name="cmd"/>
<attribute name="output" default="dont.care"/>
<attribute name="input" default="/dev/null"/>
<sequential>
<exec executable="psql" failonerror="true"
outputproperty="@{output}" input="@{input}">
<env key="PGPASSWORD" value="${db.password}"/>
<arg value="-q"/>
<arg value="-U"/>
<arg value="${db.user}"/>
<arg value="-d"/>
<arg value="${database}"/>
<arg value="-t"/>
<arg value="-c"/>
<arg value="@{cmd}"/>
</exec>
</sequential>
</macrodef>
This work fine.
On Windows, however, my build was failing. Running with "ant -v" shows the
following:
install-data:
[exec] Current OS is Windows XP
[exec] Redirecting input from file
[exec] Setting environment variable: PGPASSWORD=<redacted>
[exec] Executing 'psql' with arguments:
[exec] '-q'
[exec] '-U'
[exec] 'postgres'
[exec] '-d'
[exec] 'gm'
[exec] '-t'
[exec] '-c'
[exec] 'COPY Planet FROM STDIN WITH CSV DELIMITER AS ',' QUOTE AS
'"' ESCAPE AS '"''
[exec]
[exec] The ' characters around the executable and arguments are
[exec] not part of the command.
[exec] Opening
C:\workspaces\GalaxyMaster\DB\Databases\GalaxyMaster\dist\db\Data\Planet.csv
[exec] ERROR: COPY quote must be a single one-byte character
BUILD FAILED
C:\workspaces\GalaxyMaster\DB\Databases\GalaxyMaster\build.xml:244: The
following error occurred while executing this line:
C:\workspaces\GalaxyMaster\DB\Databases\GalaxyMaster\build.xml:52: exec
returned: 1
at
org.apache.tools.ant.ProjectHelper.addLocationToBuildException(ProjectHelper.java:508)
at
org.apache.tools.ant.taskdefs.MacroInstance.execute(MacroInstance.java:397)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
at org.apache.tools.ant.Task.perform(Task.java:348)
at org.apache.tools.ant.Target.execute(Target.java:357)
at org.apache.tools.ant.Target.performTasks(Target.java:385)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1337)
at org.apache.tools.ant.Project.executeTarget(Project.java:1306)
at
org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
at
org.eclipse.ant.internal.ui.antsupport.EclipseDefaultExecutor.executeTargets(EclipseDefaultExecutor.java:32)
at org.apache.tools.ant.Project.executeTargets(Project.java:1189)
at
org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.run(InternalAntRunner.java:423)
at
org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.main(InternalAntRunner.java:137)
Caused by: C:\workspaces\GalaxyMaster\DB\Databases\GalaxyMaster\build.xml:52:
exec returned: 1
at org.apache.tools.ant.taskdefs.ExecTask.runExecute(ExecTask.java:636)
at org.apache.tools.ant.taskdefs.ExecTask.runExec(ExecTask.java:662)
at org.apache.tools.ant.taskdefs.ExecTask.execute(ExecTask.java:487)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
at org.apache.tools.ant.Task.perform(Task.java:348)
at org.apache.tools.ant.taskdefs.Sequential.execute(Sequential.java:62)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
at org.apache.tools.ant.Task.perform(Task.java:348)
at
org.apache.tools.ant.taskdefs.MacroInstance.execute(MacroInstance.java:394)
... 15 more
The workaround is to change the macro invocation as follows:
<tpsqlcmd cmd="COPY Planet FROM STDIN WITH CSV DELIMITER AS ','
QUOTE AS '""' ESCAPE AS '""'"
input="${dist.db.data}${file.separator}Planet.csv"/>
Note that I had to double the " references. Indeeds, if I run the psql
command by hand from a C:> prompt, I also have to double the quotes, but I
believe that's because I have to specify it like this:
C:>psql -q -U postgres -d gm -t -c "COPY Planet FROM STDIN WITH CSV DELIMITER
AS ',' QUOTE AS '""' ESCAPE AS '""'" < dist\db\Data\Planet.csv
Note that the COPY statement is passed as a single value after the -c switch. I
expected that using <exec> and <value> I wouldn't have to do that.
Is this a bug in ANT, or do I just not understand how the Windows
CreateProcess() call expects its arguments? As indicated, I can work around
this, but it requires having OS-dependent targets in my script, which I'm not
thrilled with.
This is using ANT 1.7.1 inside Eclipse 3.5.2.
--
Rick Genter
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]