Power Builder - Datawindow expecting string - powerbuilder

I am having this error in my datawindow search function "Expecting STRING expression" Can anyone help me solve the issue. Below is my codes.
In my headerlist ue_search () returns (none) event
string s_criteria
openwithparm(w_fm210search, parent)
s_criteria = Message.StringParm
This.TriggerEvent("ue_findrec", 0, s_criteria)
And in my headerlist ue_findrec () returns (none) event
string PassedString
long l_row, l_count
PassedString = String(Message.LongParm, "address")
if trim(PassedString) <> "NULL" then
// find row
l_count = This.RowCount()
l_row = This.Find(PassedString, 1, l_count)
if l_row = 0 then
gucc_function.uof_message(032)
l_row = 1
end if
If l_row >= 0 then
This.ScrollToRow(l_row)
This.SelectRow(0, FALSE)
This.SelectRow(l_row, TRUE)
end if
end if

I suggest examining this line in your code:
PassedString = String(Message.LongParm, "address")
Generally when you trigger an event with parameters, those parameters are what you use within the event. They are referenced by the names you gave them when you created the event (or the names PB has assigned to them if they not user defined).
I suspect your Message object contains incorrect or NULL values.

Related

How to import Excel file into DataWindow

I want to import the .xlsx file into PowerBuilder DataWindow, I know we can able to do it with CSV format, but the user wants to use the xlsx format, Please let me know if there are any options to import.
you can import xls like this (this is our import function). Of course you have to know where to put each columns value from the excel to the datawindow. I think you do not need such a sophisticated solution, but there are the main guidelines:
int li_rtn, li_i
string ls_range
long ll_excel_rows, ll_max_rows, ll_max_columns
long ll_i, ll_j
string lsa_column_names[], ls_mod
long lla_column_pos[]
long ll_row
int li_rc
string las_truncated_data[]
string ls_errorMessage
oleobject lole_excel, lole_workbook, lole_worksheet
TRY
lole_excel = create oleobject
li_rtn = lole_excel.ConnectToNewObject("excel.application")
if li_rtn <> 0 then
ls_errorMessage = "Error running MS Excel api"
li_rtn = -1
else
li_rtn = 1
lole_excel.WorkBooks.Open(as_filepath)
lole_workbook = lole_excel.application.workbooks(1)
int li_sheetnum
IF IsNumber(as_sheet) THEN
li_sheetnum = Integer(as_sheet)
ELSE
li_sheetnum = uof_pub_excel_get_sheet_byname(as_sheet, lole_workbook)
END IF
lole_worksheet = lole_workbook.worksheets(li_sheetnum)
ll_max_rows = lole_worksheet.UsedRange.Rows.Count
ll_max_columns = lole_worksheet.UsedRange.Columns.Count
string lsa_tmp[]
lsa_column_names = f_split(f_trim(as_imported_columns,";"), ";")
FOR ll_i = 1 TO UpperBound(lsa_column_names)
IF (pos(lsa_column_names[ll_i], ":")>0) THEN
lsa_tmp = f_split(lsa_column_names[ll_i], ":")
lla_column_pos[UpperBound(lla_column_pos)+1] = long(lsa_tmp[2])
lsa_column_names[ll_i] = lsa_tmp[1]
END IF
NEXT
string ls_cellValue, ls_coltype, ls_value
int li_idx_col, li_statrRow
boolean lb_copyData = false
int li_col_offset, li_vlen
li_statrRow = ai_start_row
IF (UpperBound(lla_column_pos)=0) THEN
IF (UpperBound(lsa_column_names)<ll_max_columns) THEN ll_max_columns = UpperBound(lsa_column_names)
FOR ll_j = li_statrRow TO ll_max_rows
li_col_offset = 0
ll_row = adw_dest.insertRow(0) // insert new row
FOR ll_i = 1 TO (ll_max_columns)
ls_cellValue = String(lole_worksheet.cells(ll_j,ll_i).value)
IF (lsa_column_names[(ll_i)] = "") THEN
li_col_offset++
continue
END IF
// li_rc = adw_dest.SetItem(ll_row, lsa_column_names[(ll_i)], lole_worksheet.cells(ll_j, (ll_i)).value)
ls_value = String(lole_worksheet.cells(ll_j, ll_i).value)
ls_coltype = adw_dest.describe(lsa_column_names[(ll_i)]+'.ColType')
// Checking length of string data
IF (pos(ls_coltype, "char")>0) THEN
li_vlen = integer(replace(left(ls_coltype, len(ls_coltype)-1), 1, 5, ""))
IF (li_vlen > 0 AND len(ls_value)>li_vlen) THEN
li_rtn = -2
ls_value = left(ls_value, li_vlen)
IF (f_array_indexof(las_truncated_data, lsa_column_names[ll_i])<1) THEN
las_truncated_data[UpperBound(las_truncated_data)+1] = lsa_column_names[ll_i]
END IF
END IF
END IF
li_rc = guo_common_utilities.uof_pub_set_dw_value(adw_dest, ll_row, lsa_column_names[(ll_i)], ls_value, ls_coltype)
NEXT
NEXT
ELSE
FOR ll_j = li_statrRow TO ll_max_rows
ll_row = adw_dest.insertRow(0) // insert new row
FOR ll_i = 1 TO UpperBound(lla_column_pos)
ls_cellValue = String(lole_worksheet.cells(ll_j,lla_column_pos[ll_i]).value)
adw_dest.SetItem(ll_row, lsa_column_names[ll_i], ls_cellValue)
NEXT
NEXT
END IF
end if
CATCH ( runtimeerror lo_rte)
li_rtn = -1
ls_errorMessage = "MS Excel api runtime error"
FINALLY
// Quit
IF (IsValid(lole_excel)) THEN
lole_excel.application.quit()
lole_excel.DisconnectObject()
END IF
destroy lole_Excel
destroy lole_workbook
destroy lole_worksheet
END TRY
uo_nv_response luo_return
luo_return = create uo_nv_response
luo_return.ii_errorCode = li_rtn
IF (UpperBound(las_truncated_data)>0) THEN
luo_return.is_errorMessage = "Zeichenkette von "
FOR li_i = 1 TO UpperBound(las_truncated_data)
luo_return.is_errorMessage += las_truncated_data[li_i] + ", "
NEXT
luo_return.is_errorMessage = Left(luo_return.is_errorMessage, Len(luo_return.is_errorMessage)-2)
luo_return.is_errorMessage += " wurde abgeschnitten"
ELSE
luo_return.is_errorMessage = ls_errorMessage
END IF
return luo_return
Here are some missing functions:
global type f_array_indexof from function_object
end type
forward prototypes
global function integer f_array_indexof (any aa_array[], any aa_element)
end prototypes
global function integer f_array_indexof (any aa_array[], any aa_element);int li_count
FOR li_count = 1 TO UpperBound(aa_array)
IF (lower(aa_array[li_count]) = lower(aa_element)) THEN
return li_count
END IF
NEXT
return -1
end function
f_split:
global type f_split from function_object
end type
forward prototypes
global function boolean f_split (string as_str)
global function any f_split (string as_str, string as_delimiter)
end prototypes
global function any f_split (string as_str, string as_delimiter);long ll_pos1, ll_pos2, i
String lsa_split[]
ll_pos1 = Pos(as_str, as_delimiter)
ll_pos2 = 0
i = 1
if (ll_pos1 = 0 and Len(as_str)>0) then lsa_split[1] = as_str
do while ll_pos1 > 0
lsa_split[i] = ''
if( i = 1 )then
lsa_split[i] = mid (as_str, 1, ll_pos1 - 1)
ll_pos2 = ll_pos1
else
ll_pos2 = Pos (as_str, as_delimiter, ll_pos1 + 1)
if( ll_pos2 = 0 )then // it's the end :)
lsa_split[i] = mid (as_str, ll_pos1 + 1, Len(as_str) - ll_pos1 )
else
lsa_split[i] = mid (as_str, ll_pos1 + 1, ll_pos2 - ll_pos1 - 1)
end if
end if
ll_pos1 = ll_pos2
i = i + 1
loop
//lsa_split[i] = Right( as_str, Len(as_str) - ll_pos1 )
return lsa_split
end function
f_trim:
global type f_trim from function_object
end type
forward prototypes
global function string f_trim (string as_string, character ac_remove)
end prototypes
global function string f_trim (string as_string, character ac_remove);if (Isnull(as_string) or Isnull(ac_remove)) then return as_string
do while (left(as_string, 1) = ac_remove)
as_string = right(as_string, Len(as_string)-1)
loop
do while (right(as_string, 1) = ac_remove)
as_string = left(as_string, Len(as_string)-1)
loop
return as_string
end function
public function integer uof_pub_excel_get_sheet_byname (string as_sheetname, oleobject aole_workbook);int li_sheets_count, li_i
li_sheets_count = aole_workbook.worksheets.count
FOR li_i = 1 TO li_sheets_count
IF (aole_workbook.worksheets(li_i).name = as_sheetname) THEN return li_i
NEXT
return 0
end function
If the spreadsheet is defined correctly (header row contains the column name, rows 2-n contain the data), then you can define an ODBC connection to it, and treat it just like a database.
You paint the datawindow directly against the spreadsheet - no coding at all!! (Other than setting SQLCA and calling dw.Retrieve(), of course)
I would open the workbook with OLE, save it as format 8 (DBase3) with a dbf extension, then import it in the DataWindow.
Save it to a text file using OLE and then import it. Below piece of code does this
li_return = GetFileOpenName('Select a spreadsheet to upload - XLS or XLSX formats only', ls_path, ls_file, 'xl*', "All Excel Files (*.xl*),*.xl*", "%userprofile%\desktop")
//Save the file as Text using OLE and then import
MyExcelFile = Create OLEObject
If MyExcelFile.ConnectToObject(ls_path) < 0 then
MessageBox('Import Error', 'Unable to load spreadsheet. Please check if the file is open')
Return
End If
ls_txt_path = Mid(ls_path, 1, Pos(ls_path, '.xl') - 1) + '.txt'
FileDelete(ls_txt_path)
MyExcelFile.Application.WorkBooks(1).SaveAs(ls_txt_path, 21);
MyExcelFile.Application.DisplayAlerts = False
MyExcelFile.Application.WorkBooks(1).Close();
Destroy MyExcelFile;
Now import the file with the name ls_txt_path into the datawindow

Lua - Using string.find to return true if between 2 special characters

I need a pattern that will work with string.find (or string.match if necessary) that will return true if a "table path" string matches. This is my function:
local function FindValueFromPattern(myTable, pattern, previousPath)
for key, value in pairs(myTable) do
local path;
if (not previousPath) then
path = key;
else
path = string.format("%s.%s", previousPath, key);
end
if (path:find(pattern)) then
return value;
elseif (type(value) == "table") then
value = FindValueFromPattern(value, pattern, path);
if (value ~= nil) then
return value;
end
end
end
return nil;
end
local tbl = {}
tbl.settings = {};
tbl.settings.module = {};
tbl.settings.module.appearance = {};
tbl.settings.module.appearance.color = "blue";
print(FindValueFromPattern(tbl, "settings.module.appearance.color")); -- prints "blue";
The code above works BUT I want to now change the pattern to:
"module.<ANY>.color" where <ANY> is any child table of "module" and also has a child table called "color", so when traversing down the table, a value will be returned regardless of what table is used (does not have to be the appearance table):
-- should also print "blue" ("setting." should not be required);
print(FindValueFromPattern(tbl, "module.<ANY>.color"));
Rather than returning found values straight away, I may have to change the logic to insert found values in a table and then return the table after the for-loop but I wrote this quickly to illustrate the problem.
So the question is, what would that pattern look like? Thank you.
What you do there is extremely inefficient. A much better approach would be to split the string at each . and just index the table.
A simple version that doesn't accept "any" could look like this
function findintable(tab, path)
local pos = path:find(".", 1, true)
if pos then
local tab = tab[path:sub(1, pos-1)]
if not type(tab) then error("Expected value to be table, got "..type(tab), 1) end
return findintable(tab, path:sub(pos+1, -1))
else
return tab[path]
end
end
Adding the possibility for an any key (he... he... he...) would add some complexity and needs a loop, but it's also doable
function findintable(tab, path)
local pos = path:find(".", 1, true)
if not pos then
return tab[path]
end
local key, rest = path:sub(1, pos-1), path:sub(pos+1, -1)
if key == "*" then
for k, v in pairs(tab) do
if type(v)~="table" then return end
local res = findintable(v, rest)
if res then return res end
end
return
else
local tab = tab[path:sub(1, pos-1)]
if not type(tab) then error("Expected value to be table, got "..type(tab), 1) end
return findintable(tab, path:sub(pos+1, -1))
end
end
This should do what you want. Just change the "*" to whatever you want the placeholder to be.
I used gmatch with the pattern %.*([^.]+) to iterate through each key in the keys provided.
This function could be changed to output a table of all colors found, but currently only returns a single value. The value returned is the color found or nil if no matches were found.
function FindValueFromPattern(tab, keys)
local t_ref = tab
for k in keys:gmatch("%.*([^.]+)") do
if k == "<ANY>" and type(t_ref) == "table" then
local temp1
local temp2
for any in pairs(t_ref) do
local new_keys = keys:gsub(k, any)
temp1 = FindValueFromPattern(tab, new_keys)
new_keys = keys:gsub(k, any .. ".<ANY>")
temp2 = FindValueFromPattern(tab, new_keys)
if temp1 or temp2 then
break
end
end
t_ref = temp1 or temp2
break
else
if t_ref == nil or type(t_ref) ~= "table" then
t_ref = nil
break
end
t_ref = t_ref[k]
end
end
return t_ref
end
Example use:
sample = {
a = {
b = {
c = {
color = "blue",
},
roloc = 1,
color = "red",
},
d = {
e = {
color = "purple",
},
roloc = "wolley",
color = "yellow",
},
}
}
colorFound = FindValueFromPattern(sample, "a.<ANY>.color")
if colorFound then
print("Found: " .. colorFound )
else
print("No matches found")
end
>> Found: red
Keep in mind the behavior is nondeterministic, it is possible for the output to be yellow rather then red, and it cannot be known which it will be until the code is run.

Error While running SQL Stored procedure thru Access 2010 VBA

I am trying to run sql stored procedure from Access form, which is throwing error
procedure or function has too many arguments
while I have only one parameter passing to stored procedure.
I am using sql server 2012.
What's wrong with my code?
ALTER Procedure [dbo].[SP_SSIS_pkg_Rfnd_BSP] (#ExcelFilePath sql_variant)
As
begin
DECLARE #FolderName nvarchar(128) = 'Import_RAData_BSP'
DECLARE #ProjectName nvarchar(128) = 'SSIS_Rfnd_App_BSP'
DECLARE #PackageName nvarchar(260) = 'pkg_Rfnd_BSP.dtsx'
DECLARE #LoggingLevel varchar(16) = 'Basic'
DECLARE #Use32BitRunTime bit = 0
DECLARE #ReferenceID bigint = NULL
DECLARE #ObjectType smallint = 50
DECLARE #ExecutionID bigint
Set NOCOUNT ON
/* Call the catalog.create_execution stored procedure
to initialize execution location and parameters */
Exec SSISDB.catalog.create_execution
#package_name = #PackageName
,#execution_id = #ExecutionID Output
,#folder_name = #FolderName
,#project_name = #ProjectName
,#use32bitruntime = #Use32BitRunTime
,#reference_id = #ReferenceID
/* Populate the #ExecutionID parameter for OUTPUT */
Select #ExecutionID As Execution_Id
/* Create a parameter (variable) named #Sql */
Declare #logging_level smallint
/* Decode the Logging Level */
Select #logging_level = Case
When Upper(#LoggingLevel) = 'BASIC'
Then 1
When Upper(#LoggingLevel) = 'PERFORMANCE'
Then 2
When Upper(#LoggingLevel) = 'VERBOSE'
Then 3
Else 0 /* 'None' */
End
/* Call the catalog.set_execution_parameter_value stored
procedure to update the LOGGING_LEVEL parameter */
Exec SSISDB.catalog.set_execution_parameter_value
#ExecutionID
,#object_type = 30
,#parameter_name = N'ExcelFilePath'
,#parameter_value = #ExcelFilePath
/* Call the catalog.set_execution_parameter_value stored
procedure to update the LOGGING_LEVEL parameter */
Exec SSISDB.catalog.set_execution_parameter_value
#ExecutionID
,#object_type = #ObjectType
,#parameter_name = N'LOGGING_LEVEL'
,#parameter_value = #logging_level
/* Call the catalog.start_execution (self-explanatory) */
Exec SSISDB.catalog.start_execution #ExecutionID
end
VBA Function to execute stored procedure
Function Import_RA_Data(ByVal FileName As String, FName As String)
On Error GoTo ErrHandler:
Dim objConn As New ADODB.Connection
Dim objCmd As New ADODB.Command
Dim objParm As New ADODB.Parameter
Dim objRs As New ADODB.Recordset
Dim FilePath As String
' Set CommandText equal to the stored procedure name.
objCmd.CommandText = "SP_SSIS_pkg_Rfnd_BSP"
objCmd.CommandType = adCmdStoredProc
' Connect to the data source.
Set objConn = GetNewConnection
objCmd.ActiveConnection = objConn
' Automatically fill in parameter info from stored procedure.
objCmd.Parameters.Refresh
objParm.Value = FilePath
Set objParm = objCmd.CreateParameter("#ExcelFilePath", adVariant, adParamInput, , objParm.Value)
objCmd.Parameters.Append objParm
objRs.CursorType = adOpenStatic
objRs.CursorLocation = adUseClient
objRs.LockType = adLockOptimistic
objRs.Open objCmd
' Execute once and display...
Set objRs = objCmd.Execute
'clean up
objRs.Close
objConn.Close
Set objRs = Nothing
Set objConn = Nothing
Set objCmd = Nothing
Set objParm = Nothing
Exit Function
ErrHandler:
'clean up
If objRs.State = adStateOpen Then
objRs.Close
End If
If objConn.State = adStateOpen Then
objConn.Close
End If
Set objRs = Nothing
Set objConn = Nothing
Set objCmd = Nothing
Set objParm = Nothing
If Err <> 0 Then
MsgBox Err.Source & "-->" & Err.Description, vbCritical, "Error"
End If
End Function
It looks like this code is adding the same parameter twice. The Refresh method populates the parameter collection and then you are manually adding the same parameter again, and only one of the parameter values is set.
' Automatically fill in parameter info from stored procedure.
objCmd.Parameters.Refresh
objParm.Value = FilePath
Set objParm = objCmd.CreateParameter("#ExcelFilePath", adVariant, adParamInput, , objParm.Value)
objCmd.Parameters.Append objParm
One way to fix is to remove the CreateParameter:
objCmd.Parameters.Refresh
objCmd.Parameters("#ExcelFilePath").Value = FilePath
Alternatively, you could remove the Refresh and create the parameters manually. The advantage of this method is it avoids the extra round trip to retrieve parameter meta-data.
Set objReturnCodeParm = objCmd.CreateParameter("#RETURN_CODE", adInteger, adParamReturnValue)
objCmd.Parameters.Append objReturnCodeParm
Set objParm = objCmd.CreateParameter("#ExcelFilePath", adVariant, adParamInput, , FilePath)
objCmd.Parameters.Append objParm
Note that sp_ should be avoided as a stored procedure name prefix. That prefix is used to designate system stored procedures.
EDIT:
catalog.start_execution will execute the package asynchronously so the wrapper proc will finish before it completes. If you want to wait, add a SYNCHRONIZED parameter like the example below. Be aware that the default ADO command timeout is 30 seconds so you may need to increase the value by setting objCmd.CommandTimeout to a higher value, or zero for no timeout.
EXEC SSISDB.catalog.set_execution_parameter_value
#ExecutionID
,#object_type = #ObjectType --this must be 50
,#parameter_name = N'SYNCHRONIZED'
,#parameter_value = 1;

Google App Engine - Get from repeated StructuredProperty

I have the following structures:
class UserOther(ndb.Model):
other_type = ndb.StringProperty(indexed = True)
other_data = ndb.StringProperty(indexed = False)
class User(ndb.Model):
name = ndb.StringProperty(default = "NULL", indexed = False)
email = ndb.StringProperty(default = "NULL", indexed = False)
active = ndb.BooleanProperty(default = True)
others = ndb.StructuredProperty(UserOther, repeated = True)
updated_at = ndb.DateTimeProperty(auto_now = True)
How can I use an User key id and a string for other_type(like "job") to get and be able to edit that information. I tried using the ancestor parameter, but perhaps I didn't do that correctly.
user_key = ndb.Key("User", user_id)
user = user_key.get()
other = UserOther.query(UserOther.other_type == "job", ancestor = user_key).get()
So if i print my user looks like this :
1425436064.0User(key=Key('User', 5171003185430528), active=True, email=u'NULL', name=u'NULL', others=[UserOther(other_data=u'0', other_type=u'job'), UserOther(other_data=u'0', other_type=u'times_worked'), UserOther(other_data=u'0', other_type=u'times_opened')], updated_at=datetime.datetime(2015, 3, 6, 10, 35, 24, 838078))
But if I print the job variable it is
1425436759.0None
What I would do is get the user (by id) and then filter the 'others' in code:
user = User.get_by_id(user_key_id)
for other in user.others:
if other.other_type == 'job':
print other.other_data # do edits
You've misunderstood how to query for structured properties. The UserOther entity doesn't live on its own, it's part of the relevant User entity, so that's what you need to query.
The documentation explains exactly how to do this, but in summary you would do:
job = User.query(User.others.other_type == "job").get()

Datastore keeps on retrieving after the data is populated

In the datawindow report's detail section, there was a computed field and inside the computed field is the PB function which holds 2 string passed by value arguments and a return type of string. Once the retrieving is finished and data is populated, the datawindow keeps on retrieving as I've watched from the SQL profiler but there was no error message window.
What seems to be the problem in this function?
/*
Function name : f_generate_serialrange
Return Type : String
Argument Type : Argument Name :
String loc
String id
*/
Long ll_row
Double ld_serialno1, ld_serialno2, ld_start, ld_end, ld_result, ld_next, ld_prev = 0
Double ld_row, ld_count = 0, ld_countaccept = 0, ld_serialcount
String ls_sum, ls_start, ls_prev, ls_next, ls_serialno2
DataStore lds_getserial
lds_getserial = Create DataStore
lds_getserial.DataObject = 'dw_delivery_receipt_serialno1'
lds_getserial.SetTransObject(SQLCA)
lds_getserial.Retrieve(loc,palletid)
ll_row =lds_getserial.RowCount()
IF lds_getserial.RowCount() > 0 THEN
FOR ld_row = 1 TO lds_getserial.RowCount()
ld_serialno1 = Double(lds_getserial.GetItemString(ld_row,'serialno'))
ls_serialno2 = lds_getserial.GetItemString(ld_row,'serialno2')
IF ld_count = 0 THEN
ld_start = ld_serialno1
ls_start = ls_serialno2
ld_count++
ELSE
ld_next = ld_serialno1
ls_next = ls_serialno2
IF ld_prev = 0 THEN
ld_result = ld_next - ld_start
ELSE
ld_result = ld_next - ld_prev
END IF
IF ld_result > 1 THEN
IF ls_prev = '' THEN
ls_sum += String(ls_start) +'~n'
ELSE
ls_sum += String(ls_start) +' - '+String(ls_prev)+'~n'
END IF
ld_start = ld_next
ls_start = String(ls_next)
ld_prev = 0
ls_prev = ''
ELSE
ld_prev = ld_next
ls_prev = String(ls_next)
END IF
END IF
NEXT
IF ls_prev = '' THEN
ls_sum +=String(ls_start)+'~n'
ELSE
ls_sum +=String(ls_start)+' - '+String(ls_prev)+'~n'
END IF
END IF
//MessageBox('System Message','Serial Range has been successfully retrieved.',INformation!)
Destroy (lds_getserial)
RETURN ls_sum
You shouldn't call a function that uses the database in a computed field because many things will cause PowerBuider to calculate the computed field again. Instead add a dummy column to the DataWindow's SELECT statement. After you retrieve you can loop through the rows and use code similar to your function to populate the dummy column with the serial number range. The reason I say "similar to your function" is that you should only create and connect the DataStore once, then retrieve it with the parameters for each row.

Resources