NpgSqlCopyIn recommended error handling - npgsql

I have following code for PostgreSQL bulk inserts using npgsql from .Net code.
try
{
var items = GetSourceData(task);
connection.Open();
var command = new NpgsqlCommand(null, connection);
BeforeDestinationCommandExecution(task, command);
command.CommandText = string.Format("COPY {0} FROM STDIN", task.DestinationTable);
command.CommandTimeout = 3600;
var cin = new NpgsqlCopyIn(command, connection);
var rowCount = 0;
try
{
cin.Start();
foreach (var item in items)
{
var b = StreamEncoding.GetBytes(ConvertSourceData(item));
cin.CopyStream.Write(b, 0, b.Length);
++rowCount;
}
cin.End();
log.Debug(string.Format("Table {0} contained {1:N0} records", task.DestinationTable, rowCount));
}
catch (Exception e)
{
log.ErrorException("Exception caught in inner try block - MigrateWithCopyMode", e);
try
{
// send CopyFail to server
cin.Cancel("Undo copy");
}
catch (Exception cancelException)
{
// we should get an error in response to our cancel request:
if (!cancelException.ToString().Contains("Undo copy"))
{
throw new Exception("Failed to cancel COPY: " + cancelException + " upon failure: " + e);
}
}
throw;
}
finally
{
_migrationCounts.Add(task.DestinationTable, rowCount);
}
For last 2 days I've experienced unhandled exception while executing the code. After some investigation and attaching code to UnhandledException event.
System.AppDomain.CurrentDomain.UnhandledException += unhandledException;
I've found that the problem was in data being processed.
Error [16] [HubAdapterMsSqlPostgres] Unhandled exception Npgsql.NpgsqlException:
null value in column "name_ru" violates not-null constraint
Severity: ERROR
Code: 23502
at Npgsql.NpgsqlState.<ProcessBackendResponses_Ver_3>d__a.MoveNext()
at Npgsql.NpgsqlState.IterateThroughAllResponses(IEnumerable`1 ienum)
at Npgsql.NpgsqlConnector.NpgsqlContextHolder.ProcessServerMessages()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
This error was generated on different thread. I guess after calling cin.CopyStream.Write(b, 0, b.Length); from previous code example.
My question is
What is recommended way to handle such error to be able omit rows with wrong values and continue in bulk insert operation
Thank you

You're trying to import data containing rows which are incompatible with your table definition - they lack data for a non-nullable column. COPY is an all-or-nothing process: either the entire process succeeds, or it fails entirely. Therefore, you have to either:
* Clean up your input first, removing the offending rows (this would involve parsing your input, which may be difficult), or
* Temporarily remove the non-null constraint on your table, perform the COPY, delete the problematic rows from the table and reinstate the constraint. This may or may not be appropriate depending on your usage scenario.
Regardless, you're using Npgsql 2.x, which is very old by now and unmaintained. It's highly recommended you upgrade to the latest version of Npgsql.

Related

solrj returns the same result for different queries

Here is my code:-
SolrClient client = new HttpSolrClient.Builder("http://arlmsendeavour01:8983/solr/ImageMatch").build();
SolrQuery query = new SolrQuery();
query.setRequestHandler("/select");
//System.currentTimeMillis();
String q = "{!cache=false}*:*&debugQuery=true&sort=lirefunc(eh,\"opKg0dKEtZOSsaSBkfPChsTEopGykqHExYTEw5GylbKx8KKXkqHRww==\")+asc";
query.setQuery("q");
QueryResponse response = null;
try {
response = client.query(query);
} catch (SolrServerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SolrDocumentList results = response.getResults();
for (int i = 0; i < results.size(); ++i) {
System.out.println(results.get(i)/*.getFieldValue("id")*/);
}
I am using a function query lirefunc where the first parameter defines whether it is a color or edge or texture and the second parameter is the extracted feature from the image. Every time i run the code that is even for different images and different features I get the same output as if it is extracted from the solr xml. The out put remains the same for all the types of queries. Where am I going wrong?
query.setQuery("q"); - this sets the query to the string "q". I'm certain that's not what you meant to do.
The setQuery method isn't used to set a query string either - it's used to set whatever is present in the q parameter (the query) to Solr.
There are separate methods for each part of the request to Solr in SolrJ.
To set the sort= parameter, use addSort:
query.addSort(SortClause.desc("lirefunc(eh,\"opKg0dKEtZOSsaSBkfPChsTEopGykqHExYTEw5GylbKx8KKXkqHRww==\")"));

Npgsql connection to PostgreSql: Array datatype

I am working in Visual Studio 2015 using Visual Basic. I am connecting to a PostgreSql database using Npgsql. There seems to be a problem with the Array Datatype - or hopefully I am doing something wrong. Some of my code:
Dim aWriter As Npgsql.NpgsqlBinaryImporter
Dim Keys() As String
N_Domain = UBound(myKey_Name, 1)
N_Record = UBound(myKey_Name, 2)
ReDim Keys(0 To N_Domain - 1)
aWriter = Connect.BeginBinaryImport _
("COPY ""GAMS Sets"" FROM STDIN (FORMAT BINARY)")
For Rec = 1 To N_Record
For Dom = 1 To N_Domain
Keys(Dom - 1) = myKey_Name(Dom, Rec)
Next Dom
aWriter.StartRow()
aWriter.Write(myCase, NpgsqlDbType.Text)
aWriter.Write(SyId, NpgsqlDbType.Text)
aWriter.Write(Keys, NpgsqlDbType.Array Or NpgsqlDbType.Text)
Next Rec
aWriter.Dispose()
aWriter.Close()
When I run the code I get an error at aWriter.Dispose():
{"42804: wrong element type"}, ErrorCode: -2147467259.
What is wrong? Isn't Text Arrays supported?
Error details:
Npgsql.PostgresException was unhandled
BaseMessage=wrong element type
Code=42804
ErrorCode=-2147467259
File=arrayfuncs.c
HResult=-2147467259
InternalPosition=0
Line=1306
Message=42804: wrong element type
MessageText=wrong element type
Position=0
Routine=array_recv
Severity=ERROR
Source=Npgsql
SqlState=42804
[Where]=COPY GAMS Sets, line 1, column Keys
StackTrace:
at Npgsql.NpgsqlConnector.DoReadMessage(DataRowLoadingMode dataRowLoadingMode, Boolean isPrependedMessage)
at Npgsql.NpgsqlConnector.ReadMessageWithPrepended(DataRowLoadingMode dataRowLoadingMode)
at Npgsql.NpgsqlConnector.ReadExpecting[T]()
at Npgsql.NpgsqlBinaryImporter.Close()
at Npgsql.NpgsqlBinaryImporter.Dispose()
at ConsoleApplication1.Module1.HVL_Write_Set(String myCase, Int32 SyNr, String SyId, Int32 Dimen, String[] myDomain_Name, String[,] myKey_Name) in \\dtu-storage\hela\Documents\Visual Studio 2015\Projects\GDX API 5\GDX API 5\Module1.vb:line 305
at ConsoleApplication1.Module1.Main() in \\dtu-storage\hela\Documents\Visual Studio 2015\Projects\GDX API 5\GDX API 5\Module1.vb:line 638
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:

Saving image to database as varbinary, arraylength (part 2)

This is a followup to my previous question, which got solved (thank you for that) but now I am stuck at another error.
I'm trying to save an image in my database (called 'Afbeelding'), for that I made a table which excists of:
id: int
souce: varbinary(max)
I then created a wcf service to save an 'Afbeelding' to the database.
private static DataClassesDataContext dc = new DataClassesDataContext();
[OperationContract]
public void setAfbeelding(Afbeelding a)
{
//Afbeelding a = new Afbeelding();
//a.id = 1;
//a.source = new Binary(bytes);
dc.Afbeeldings.InsertOnSubmit(a);
dc.SubmitChanges();
}
I then put a reference to the service in my project and when I press the button I try to save it to the datbase.
private void btnUpload_Click(object sender, RoutedEventArgs e)
{
Afbeelding a = new Afbeelding();
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "JPEG files|*.jpg";
if (openFileDialog.ShowDialog() == true)
{
//string imagePath = openFileDialog.File.Name;
//FileStream fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
//byte[] buffer = new byte[fileStream.Length];
//fileStream.Read(buffer, 0, (int)fileStream.Length);
//fileStream.Close();
Stream stream = (Stream)openFileDialog.File.OpenRead();
Byte[] bytes = new Byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
string fileName = openFileDialog.File.Name;
a.id = 1;
a.source = new Binary { Bytes = bytes };
}
EditAfbeeldingServiceClient client = new EditAfbeeldingServiceClient();
client.setAfbeeldingCompleted +=new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_setAfbeeldingCompleted);
client.setAfbeeldingAsync(a);
}
void client_setAfbeeldingCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (e.Error != null)
txtEmail.Text = e.Error.ToString();
else
MessageBox.Show("WIN");
}
However, when I do this, I get the following error:
System.ServiceModel.FaultException: The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter :a.
The InnerException message was 'There was an error deserializing the object of type OndernemersAward.Web.Afbeelding.
The maximum array length quota (16384) has been exceeded while reading XML data. This quota may be increased by changing the MaxArrayLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.'.
Please see InnerException for more details.
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc) at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.ClientBase`1.ChannelBase`1.EndInvoke(String methodName, Object[] args, IAsyncResult result)
atOndernemersAward.EditAfbeeldingServiceReference.EditAfbeeldingServiceClient.EditAfbeeldingServiceClientChannel.EndsetAfbeelding(IAsyncResult result)
at OndernemersAward.EditAfbeeldingServiceReference.EditAfbeeldingServiceClient.OndernemersAward.EditAfbeeldingServiceReference.EditAfbeeldingService.EndsetAfbeelding(IAsyncResult result)
at OndernemersAward.EditAfbeeldingServiceReference.EditAfbeeldingServiceClient.OnEndsetAfbeelding(IAsyncResult result)
at System.ServiceModel.ClientBase`1.OnAsyncCallCompleted(IAsyncResult result)
I'm not sure what's causing this but I think it has something to do with the way I write the image to the database? (The array length is too big big, I don't really know how to change it)
Thank you for your help,
Thomas
looks like you need to change default reader quotas in binding, set lengths to appropriate values for you:
<readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="2147483646" maxBytesPerRead="4096" maxNameTableCharCount="5242880"/>

SQL Server CLR Integration enlisting in current transaction

I'm trying to use CLR integration in SQL Server to handle accessing external files instead of storing them internally as BLOBs. I'm trying to figure out the pattern I need to follow to make my code enlist in the current SQL transaction. I figured I would start with the simplest scenario, deleting an existing row, since the insert/update scenarios would be more complex.
[SqlProcedure]
public static void DeleteStoredImages(SqlInt64 DocumentID)
{
if (DocumentID.IsNull)
return;
using (var conn = new SqlConnection("context connection=true"))
{
conn.Open();
string FaceFileName, RearFileName;
int Offset, Length;
GetFileLocation(conn, DocumentID.Value, true,
out FaceFileName, out Offset, out Length);
GetFileLocation(conn, DocumentID.Value, false,
out RearFileName, out Offset, out Length);
new DeleteTransaction().Enlist(FaceFileName, RearFileName);
using (var comm = conn.CreateCommand())
{
comm.CommandText = "DELETE FROM ImagesStore WHERE DocumentID = " + DocumentID.Value;
comm.ExecuteNonQuery();
}
}
}
private class DeleteTransaction : IEnlistmentNotification
{
public string FaceFileName { get; set; }
public string RearFileName { get; set; }
public void Enlist(string FaceFileName, string RearFileName)
{
this.FaceFileName = FaceFileName;
this.RearFileName = RearFileName;
var trans = Transaction.Current;
if (trans == null)
Commit(null);
else
trans.EnlistVolatile(this, EnlistmentOptions.None);
}
public void Commit(Enlistment enlistment)
{
if (FaceFileName != null && File.Exists(FaceFileName))
{
File.Delete(FaceFileName);
}
if (RearFileName != null && File.Exists(RearFileName))
{
File.Delete(RearFileName);
}
}
public void InDoubt(Enlistment enlistment)
{
}
public void Prepare(PreparingEnlistment preparingEnlistment)
{
preparingEnlistment.Prepared();
}
public void Rollback(Enlistment enlistment)
{
}
}
When I actually try to run this, I get the following exception:
A .NET Framework error occurred during execution of user defined routine or aggregate 'DeleteStoredImages':
System.Transactions.TransactionException: The operation is not valid for the state of the transaction. ---> System.Transactions.TransactionPromotionException: MSDTC on server 'BD009' is unavailable. ---> System.Data.SqlClient.SqlException: MSDTC on server 'BD009' is unavailable.
System.Data.SqlClient.SqlException:
at System.Data.SqlServer.Internal.StandardEventSink.HandleErrors()
at System.Data.SqlServer.Internal.ClrLevelContext.SuperiorTransaction.Promote()
System.Transactions.TransactionPromotionException:
at System.Data.SqlServer.Internal.ClrLevelContext.SuperiorTransaction.Promote()
at System.Transactions.TransactionStatePSPEOperation.PSPEPromote(InternalTransaction tx)
at System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx)
System.Transactions.TransactionException:
at System.Transactions.TransactionState.EnlistVolatile(InternalTransaction tx, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions, Transaction atomicTransaction)
at System.Transactions.TransactionStateSubordinateActive.EnlistVolatile(InternalTransaction tx, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions, Transaction atomicTransaction)
at System.Transactions.Transaction.EnlistVolatile(IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions)
at ExternalImages.StoredProcedures.DeleteTransaction.Enlist(String FaceFileName, String RearFileName)
at ExternalImages.StoredProcedures.DeleteStoredImages(SqlInt64 DocumentID)
. User transaction, if any, will be rolled back.
The statement has been terminated.
Can anyone explain what I'm doing wrong, or point me to an example of how to do it right?
You have hopefully solved this by now, but in case anyone else has a similar problem: the error message you are getting suggests that you need to start the Distributed Transaction Coordinator service on the BD009 machine (presumably your own machine).
#Aasmund's answer regarding the Distributed Transaction Coordinator might solve the stated problem, but that still leaves you in a non-ideal state: You are tying a transaction, which locks the ImagesStore table (even if it is just a RowLock), to two file system operations? And you need to BEGIN and COMMIT the transaction outside of this function (since that isn't being handled in the presented code).
I would separate those two pieces:
Step 1: Delete the row from the table
and then, IF that did not error,
Step 2: Delete the file(s)
In the scenario where Step 1 succeeds but then Step 2, for whatever reason, fails, do one or both of the following:
return an error status code and keep track of which DocumentIDs got an error when attempting to delete the file in a status table. You can use that to manually delete the files and/or debug why the error occurred.
create a process that can run periodically to find and remove unreferenced files.

Logging SQL Statements in Android; fired by application

I have a small Android app and currently I am firing a sql statement in android to get the count of rows in database for a specific where clause.
Following is my sample code:
public boolean exists(Balloon balloon) {
if(balloon != null) {
Cursor c = null;
String count_query = "Select count(*) from balloons where _id = ?";
try {
c = getReadableDatabase().rawQuery(count_query, new String[] {balloon.getId()});
if (c.getCount() > 0)
return true;
} catch(SQLException e) {
Log.e("Running Count Query", e.getMessage());
} finally {
if(c!=null) {
try {
c.close();
} catch (SQLException e) {}
}
}
}
return false;
}
This method returns me a count 1 even when the database table is actually empty. I am not able to figure out; why that would happen. Running the same query in database gets me a count of 0.
I was wondering if it's possible to log or see in a log, all the sql queries that eventually get fired on database after parameter substitution; so that I can understand what's going wrong.
Cheers
That query will always return one record (as will any SELECT COUNT). The reason is, that the record it returns contains a field that indicates how many records are present in the "balloons" table with that ID.
In other words, the one record (c.getcount()==1) is NOT saying that the number of records found in balloons is one, rather it is the record generated by Sqlite which contains a field with the result.
To find out the number of balloons, you should c.movetofirst() and then numberOfBalloons = c.getInt(0)

Resources